library(tidyverse)
## ── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
## ✔ dplyr     1.1.4     ✔ readr     2.1.5
## ✔ forcats   1.0.0     ✔ stringr   1.5.1
## ✔ ggplot2   3.5.1     ✔ tibble    3.2.1
## ✔ lubridate 1.9.4     ✔ tidyr     1.3.1
## ✔ purrr     1.0.2     
## ── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
## ✖ dplyr::filter() masks stats::filter()
## ✖ dplyr::lag()    masks stats::lag()
## ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors
library(knitr)
library(jagsUI)
## Warning: package 'jagsUI' was built under R version 4.4.3
library(DiagrammeR)
## Warning: package 'DiagrammeR' was built under R version 4.4.3
set.seed(1019)

Seed is set to 1019 for reproducibility.

Data

Manual data, pen-wise, inclusive of multiple broods.

dflongforcount <- data.frame(
  dose=factor(c(rep("cont",6),rep("low",7),rep("med",6),rep("high",8)),
              levels=c("cont","low","med","high")),
  dosenum=c(rep(0.000121,6),rep(0.121,7),rep(0.45,6),rep(2.04,8)),
  pen=c(31,32,33,34,35,35,36,37,38,38,39,40,40,41,42,43,43,44,45,46,46,46,47,48,48,48,50),
  clutch=c(1,1,1,1,1,2,1,1,1,2,1,1,2,1,1,1,2,1,1,1,2,3,1,1,2,3,1),
  numhatched=c(3,2,2,1,0,0,4,1,0,3,3,0,0,3,0,0,0,1,1,0,0,0,2,0,0,0,2)
)

dflongforcount$failure <- ifelse(dflongforcount$numhatched==0,1,0)

JAGS setup and run of Poisson GLM

jags.data <- list(y=dflongforcount$numhatched,
                  conc=dflongforcount$dosenum,
                  n=nrow(dflongforcount))

cat(file="model_AMKE_poisson_eggs hatched by normal dose.txt","
  model{
  #priors and linear models
  alpha ~ dnorm(log(3),100) # mean and precision in jags precision is inverse of the variance, so 1/sigma^2 and in this case suggests the priors are mean=0, sd=0.1 (exp(0.1) on the real scale) (sqrt(1/100))
  beta ~ dnorm(0,0.001)
    
  #likelihood for the poisson GLM
  for(i in 1:n){
    y[i] ~ dpois(lambda[i]) #stochastic
    log(lambda[i]) <- alpha + beta * conc[i]
  }
  mean.exp.count <- exp(alpha)
}
")

inits <- function(){list(alpha=rnorm(1,0,1),beta=rnorm(1,0,1))}

parameters <- c("alpha","beta","mean.exp.count","lambda")

ni <- 50000
nb <- 10000
nc <- 3
nt <- 10
na <- 1000

out1 <- jags(jags.data, inits, parameters, "model_AMKE_poisson_eggs hatched by normal dose.txt", n.iter=ni, n.burnin=nb, n.chains=nc, n.thin=nt, n.adapt=na, parallel=T)
## 
## Processing function input....... 
## 
## Done. 
##  
## Beginning parallel processing using 3 cores. Console output will be suppressed.
## 
## Parallel processing completed.
## 
## Calculating statistics....... 
## 
## Done.
test <- data.frame(out1$sims.list[1:2])
#write_csv(test, "out1posterioralphaandbeta.csv")

\[ \alpha \sim N(3,0.1)\\ \beta \sim N(0,31.62)\\ y \sim Poisson(\lambda)\\ log(\lambda) = alpha + \beta \sum PFAS \]

JAGS output wrangling for Poisson GLM

contm <- out1$mean$lambda[1] #2.575
lowm <- out1$mean$lambda[7] #2.264
medm <- out1$mean$lambda[14] #1.605
highm <- out1$mean$lambda[20] #0.343

contl <- out1$q2.5$lambda[1] #2.164
lowl <- out1$q2.5$lambda[7] #1.906
medl <- out1$q2.5$lambda[14] #1.181
highl <- out1$q2.5$lambda[20] #0.081

contu <- out1$q97.5$lambda[1] #3.041
lowu <- out1$q97.5$lambda[7] #2.66
medu <- out1$q97.5$lambda[14] #2.034
highu <- out1$q97.5$lambda[20] #0.812


### probability of having a certain number of viable eggs

counteggdf <- data.frame(
  dose=c(0.000121, 0.121, 0.45, 2.04),
  mean=c(contm, lowm, medm, highm),
  lower=c(contl, lowl, medl, highl),
  upper=c(contu, lowu, medu, highu)
)

effectzerodf <- data.frame(
  dose=c(0.000121, 0.121, 0.45, 2.04),
  mean=c(dpois(0, lambda=contm),dpois(0, lambda=lowm),dpois(0, lambda=medm),dpois(0, lambda=highm)),
  lower=c(dpois(0, lambda=contl),dpois(0, lambda=lowl),dpois(0, lambda=medl),dpois(0, lambda=highl)),
  upper=c(dpois(0, lambda=contu),dpois(0, lambda=lowu),dpois(0, lambda=medu),dpois(0, lambda=highu)),
  hatchedeggs=rep(0,4)
)

effect3df <- data.frame(
  dose=c(0.000121, 0.121, 0.45, 2.04),
  mean=c(dpois(3, lambda=contm),dpois(3, lambda=lowm),dpois(3, lambda=medm),dpois(3, lambda=highm)),
  lower=c(dpois(3, lambda=contl),dpois(3, lambda=lowl),dpois(3, lambda=medl),dpois(3, lambda=highl)),
  upper=c(dpois(3, lambda=contu),dpois(3, lambda=lowu),dpois(3, lambda=medu),dpois(3, lambda=highu)),
  hatchedeggs=rep(3,4)
)

effect2df <- data.frame(
  dose=c(0.000121, 0.121, 0.45, 2.04),
  mean=c(dpois(2, lambda=contm),dpois(2, lambda=lowm),dpois(2, lambda=medm),dpois(2, lambda=highm)),
  lower=c(dpois(2, lambda=contl),dpois(2, lambda=lowl),dpois(2, lambda=medl),dpois(2, lambda=highl)),
  upper=c(dpois(2, lambda=contu),dpois(2, lambda=lowu),dpois(2, lambda=medu),dpois(2, lambda=highu)),
  hatchedeggs=rep(2,4)
)

effect5df <- data.frame(
  dose=c(0.000121, 0.121, 0.45, 2.04),
  mean=c(dpois(5, lambda=contm),dpois(5, lambda=lowm),dpois(5, lambda=medm),dpois(5, lambda=highm)),
  lower=c(dpois(5, lambda=contl),dpois(5, lambda=lowl),dpois(5, lambda=medl),dpois(5, lambda=highl)),
  upper=c(dpois(5, lambda=contu),dpois(5, lambda=lowu),dpois(5, lambda=medu),dpois(5, lambda=highu)),
  hatchedeggs=rep(5,4)
)

effect1df <- data.frame(
  dose=c(0.000121, 0.121, 0.45, 2.04),
  mean=c(dpois(1, lambda=contm),dpois(1, lambda=lowm),dpois(1, lambda=medm),dpois(1, lambda=highm)),
  lower=c(dpois(1, lambda=contl),dpois(1, lambda=lowl),dpois(1, lambda=medl),dpois(1, lambda=highl)),
  upper=c(dpois(1, lambda=contu),dpois(1, lambda=lowu),dpois(1, lambda=medu),dpois(1, lambda=highu)),
  hatchedeggs=rep(1,4)
)

effect4df <- data.frame(
  dose=c(0.000121, 0.121, 0.45, 2.04),
  mean=c(dpois(4, lambda=contm),dpois(4, lambda=lowm),dpois(4, lambda=medm),dpois(4, lambda=highm)),
  lower=c(dpois(4, lambda=contl),dpois(4, lambda=lowl),dpois(4, lambda=medl),dpois(4, lambda=highl)),
  upper=c(dpois(4, lambda=contu),dpois(4, lambda=lowu),dpois(4, lambda=medu),dpois(4, lambda=highu)),
  hatchedeggs=rep(4,4)
)

bigeggprobdf <- rbind(
  effectzerodf,
  effect1df,
  effect2df,
  effect3df,
  effect4df,
  effect5df
)

Table of Poisson GLM output

Probability of having a certain number of hatched eggs at each dose with confidence intervals.
Note that upper and lower are strange because some dose response are decreasing and some are increasing depending on the number of hatched eggs.

bigeggprobdf |>
  #filter(hatchedeggs==0)|>
  kable(, digits=5)
dose mean lower upper hatchedeggs
0.00012 0.07615 0.11519 0.04752 0
0.12100 0.10421 0.14819 0.06999 0
0.45000 0.20227 0.30665 0.13041 0
2.04000 0.71318 0.92599 0.44442 0
0.00012 0.19609 0.24894 0.14477 1
0.12100 0.23566 0.28293 0.18614 1
0.45000 0.32326 0.36247 0.26566 1
2.04000 0.24107 0.07120 0.36042 1
0.00012 0.25247 0.26901 0.22053 2
0.12100 0.26645 0.27010 0.24750 2
0.45000 0.25831 0.21423 0.27058 2
2.04000 0.04074 0.00274 0.14615 2
0.00012 0.21671 0.19379 0.22396 3
0.12100 0.20084 0.17190 0.21940 3
0.45000 0.13761 0.08441 0.18373 3
2.04000 0.00459 0.00007 0.03951 3
0.00012 0.13951 0.10470 0.17058 4
0.12100 0.11354 0.08205 0.14586 4
0.45000 0.05498 0.02495 0.09357 4
2.04000 0.00039 0.00000 0.00801 4
0.00012 0.07185 0.04526 0.10394 5
0.12100 0.05135 0.03133 0.07758 5
0.45000 0.01757 0.00590 0.03812 5
2.04000 0.00003 0.00000 0.00130 5

Interpolate adverse increase in probability of nest failure using Poisson GLM

Using the posterior draws, find the doses bracketing 95% probability of observing that amount of nest failure.

Background probability of having zero hatched eggs

dpois(0,lambda=contm)
## [1] 0.07614831

0.2 added risk of having zero hatched eggs

dpois(0,lambda=contm)+0.2
## [1] 0.2761483

Highest concentration where probability of having zero eggs is <0.28

i.e. “safe” concentration

### do prediction interpolation for having zero

alt.conc.pred <- seq(from=0.0001,to=3, length.out=1000)
pred2 <- array(NA,dim=c(length(alt.conc.pred),12000))
for(i in 1:12000){
  pred2[,i] <- exp(out1$sims.list$alpha[i]+out1$sims.list$beta[i]*alt.conc.pred)
}

pm2 <- apply(pred2,1, mean)
pm2l <- apply(pred2,1, quantile, probs=0.975)
pm2u <- apply(pred2,1, quantile, probs=0.025)

prob <- apply(pred2, 1, function(x) mean((x-1)<0))

dprob0 <- apply(pred2,1,function(x) mean(dpois(0,lambda=x)))
dprob0min <- apply(pred2,1,function(x) quantile(dpois(0,lambda=x), probs=0.05))
dprob0max <- apply(pred2,1,function(x) quantile(dpois(0,lambda=x), probs=0.95))

#plot(dprob0~alt.conc.pred, ylim=c(0,1))
#points(dprob0min~alt.conc.pred, col="darkgray")
#points(dprob0max~alt.conc.pred, col="darkgray")


mintwentythreshold <- max(alt.conc.pred[dprob0min<0.28])
maxtwentythreshold <- max(alt.conc.pred[dprob0max<0.28])
meantwentythreshold <- max(alt.conc.pred[dprob0<0.28])
mintwentythreshold
## [1] 1.090154
meantwentythreshold
## [1] 0.648727
maxtwentythreshold
## [1] 0.432518

Plot of predicted number of eggs

par(mai=c(2,1.2,0.1,0.3))
plot(jitter(numhatched, 0.5)~jitter(as.numeric(factor(dose))), data=dflongforcount, pch=3, ylab="Number of hatched eggs", xlab=expression(Adult~daily~dose~mg/kg~Sigma*PFAS),
     bty="n", las=1, axes=F, cex.lab=1.5)
axis(1, at=c(1,2,3,4), labels=c("0.000121", "0.121", "0.45", "2.04"), font=1, cex.axis=1.5)
axis(2, at=c(0,1,2,3,4), labels=c(0,1,2,3,4), font=1, las=1, cex.axis=1.5)
arrows(as.numeric(factor(counteggdf$dose)),counteggdf$lower,as.numeric(factor(counteggdf$dose)),counteggdf$upper, lwd=2, length=0.1, angle=90, code=3, col=c("darkgreen","blue","darkorange","red"))
points(mean~as.numeric(factor(dose)), data=counteggdf, type="l", col="darkgray", lwd=2)
points(mean~as.numeric(factor(dose)), data=counteggdf, type="p", col=c("darkgreen","blue","darkorange","red"), pch=16, cex=1.5)
points(c(1.1,1.1),c(2.95,3.05),col="purple", pch=2)
axis(1, at=c(1,2,3,4), labels=c("0.003", "3.35", "8.34", "65.84"), font=1, cex.axis=1.5, line=5)
mtext(expression(Mean~egg~mg/kg~Sigma*PFAS), side=1, line=8, font=1, cex=1.5)

par(mai=c(1,1,0.1,0.1))
plot(pm2~alt.conc.pred, log="", ylim=c(0,3), type="l", bty="n", xlim=c(-0.25,3),
     ylab="Mean number of hatched eggs", xlab=expression(paste("Adult daily dose ", Sigma,"PFAS mg/kg")), las=1,
     font=1, font.lab=1, pch=16, cex=2, lwd=2, cex.lab=1.5, cex.axis=1.5)
points(pm2l~alt.conc.pred, type="l", lty=2, col="darkgray", lwd=2)
points(pm2u~alt.conc.pred, type="l", lty=2, col="darkgray", lwd=2)
text(-0.35,2.575,"2.575", pos=4, col="darkgreen")
text(-0.35,1.264456,"1.264", pos=4, col="red")
segments(0,1.264456,1.5,1.264456, col="red")
segments(0.6757532,1.264456,0.6757532,0.5, col="black")
text(0.6757532,0.5,"0.68 mg/kg", pos=1, col="black", xpd=NA)
segments(0.4054919,1.264456,0.4054919,1.064456, col="black")
#text(0.432518,0.48,"0.43 mg/kg\nP(0 eggs)<0.28", pos=3, col="black")
text(0.4054919,1.064456,"0.41 mg/kg", pos=1, col="black")
segments(1.237296,1.264456,1.237296,1.464456, col="black")
#text(1.090154,0.18,"1.09 mg/kg\nP(0 eggs)<0.28", pos=1, col="black", xpd=NA)
text(1.237296,1.464456,"1.24 mg/kg", pos=3, col="black", xpd=NA)

max(alt.conc.pred[pm2>1.264456])
## [1] 0.6757532
max(alt.conc.pred[pm2l>1.264456])
## [1] 1.237296
max(alt.conc.pred[pm2u>1.264456])
## [1] 0.4054919
par(mai=c(1.2,1.2,0.1,0.75))
plot(dprob0~alt.conc.pred, log="", ylim=c(0,1), type="l", bty="n", xlim=c(-0.25,3),
     ylab="Probability of having 0 hatched eggs", xlab=expression(paste("Adult daily dose ", Sigma,"PFAS mg/kg")), las=1,
     font=1, font.lab=1, pch=16, cex=2, lwd=2, cex.lab=1.5, cex.axis=1.5)
points(dprob0min~alt.conc.pred, type="l", lty=2, col="darkgray", lwd=2)
points(dprob0max~alt.conc.pred, type="l", lty=2, col="darkgray", lwd=2)
abline(h=c(0,1))
text(-0.35,dpois(0,lambda=contm),"0.08", pos=4, col="darkgreen")
text(-0.35,dpois(0,lambda=contm)+0.2,"0.28", pos=4, col="red")
segments(0,dpois(0,lambda=contm)+0.2,1.5,dpois(0,lambda=contm)+0.2, col="red")
segments(0.432518,0.28,0.432518,0.48, col="black")
#text(0.432518,0.48,"0.43 mg/kg\nP(0 eggs)<0.28", pos=3, col="black")
text(0.432518,0.48,"0.43 mg/kg", pos=3, col="black")
segments(1.090154,0.28,1.090154,0.18, col="black")
#text(1.090154,0.18,"1.09 mg/kg\nP(0 eggs)<0.28", pos=1, col="black", xpd=NA)
text(1.090154,0.18,"1.09 mg/kg", pos=1, col="black", xpd=NA)
segments(0.648727,0.28,0.648727,0.08, col="black")
text(0.648727,0.08,"0.65 mg/kg", pos=1, col="black", xpd=NA)

JAGS setup and run of Bernoulli GLM

jags.data2 <- list(y=dflongforcount$failure,
                  conc=dflongforcount$dosenum,
                  n=nrow(dflongforcount))

cat(file="model_AMKE_bernoulli_eggs hatched by normal dose.txt","
  model{
  #priors and linear models
  alpha <- logit(mean.theta)
  mean.theta ~ dunif(0,0.5)
  beta ~ dnorm(0,0.001)
    
  #likelihood for the bernoulli GLM
  for(i in 1: n){
    y[i] ~ dbern(theta[i]) #stochastic
    logit(theta[i]) <- alpha + beta * conc[i]
  }
}
")

inits2 <- function(){list(mean.theta=runif(1,0, 0.5),beta=rnorm(1,0,1))}

parameters2 <- c("alpha","beta","mean.theta","theta")

ni <- 50000
nb <- 10000
nc <- 3
nt <- 10
na <- 1000

out2 <- jags(jags.data2, inits2, parameters2, "model_AMKE_bernoulli_eggs hatched by normal dose.txt", n.iter=ni, n.burnin=nb, n.chains=nc, n.thin=nt, n.adapt=na, parallel=T)
## 
## Processing function input....... 
## 
## Done. 
##  
## Beginning parallel processing using 3 cores. Console output will be suppressed.
## 
## Parallel processing completed.
## 
## Calculating statistics....... 
## 
## Done.
#jagsUI::traceplot(out2)

test2 <- data.frame(out2$sims.list[1:2])
#write_csv(test, "out1posterioralphaandbeta.csv")

\[ \alpha \sim \text{Uniform}(0,0.5)\\ \beta \sim N(0,31.62)\\ y \sim \text{Bernoulli}(\theta)\\ logit(\theta) = alpha + \beta \sum PFAS \]

JAGS output wrangling for Bernoulli GLM

contb <- out2$mean$theta[1]
lowb <- out2$mean$theta[7]
medb <- out2$mean$theta[14]
highb <- out2$mean$theta[21]

contbl <- out2$q2.5$theta[1]
lowbl <- out2$q2.5$theta[7]
medbl <- out2$q2.5$theta[14]
highbl <- out2$q2.5$theta[21]

contbu <- out2$q97.5$theta[1]
lowbu <- out2$q97.5$theta[7]
medbu <- out2$q97.5$theta[14]
highbu <- out2$q97.5$theta[21]

### probability of a failed nest (having zero hatched eggs)

failuredf <- data.frame(
  dose=c(0.000121, 0.121, 0.45, 2.04),
  mean=c(contb, lowb, medb, highb),
  lower=c(contbl, lowbl, medbl, highbl),
  upper=c(contbu, lowbu, medbu, highbu)
)



# plot(jitter(dflongforcount$failure, 0.2)~jitter(as.numeric(factor(dflongforcount$dosenum)),0.5), axes=F, pch=3, ylab="Per nest probability of failure", xlab="Diet concentration (mg/kg-d sumPFAS)", )
# lines(as.numeric(factor(dflongforcount$dosenum)), out2$mean$theta, col="blue", lwd=3)
# lines(as.numeric(factor(dflongforcount$dosenum)), out2$q2.5$theta, lwd=3, lty=2)
# lines(as.numeric(factor(dflongforcount$dosenum)), out2$q97.5$theta, lwd=3, lty=2)
# axis(1,at=unique(as.numeric(factor(dflongforcount$dosenum))), labels=sort(unique(round(dflongforcount$dosenum,2))))
# axis(2,las=1)

Plot of predicted probability of failure (zero hatched eggs)

par(mai=c(2,1.2,0.1,0.3))
plot(jitter(failure, 0.5)~jitter(as.numeric(factor(dose))), data=dflongforcount, pch=3, ylab="Probability of nest failure", xlab=expression(Adult~daily~dose~mg/kg~Sigma*PFAS),
     bty="n", las=1, axes=F, cex.lab=1.5)
axis(1, at=c(1,2,3,4), labels=c("0.000121", "0.121", "0.45", "2.04"), font=1, cex.axis=1.5)
axis(2, at=c(0,0.5,1), labels=c(0,0.5,1), font=1, las=1, cex.axis=1.5)
arrows(as.numeric(factor(failuredf$dose)),failuredf$lower,as.numeric(factor(failuredf$dose)),failuredf$upper, lwd=2, length=0.1, angle=90, code=3, col=c("darkgreen","blue","darkorange","red"))
points(mean~as.numeric(factor(dose)), data=failuredf, type="l", col="darkgray", lwd=2)
points(mean~as.numeric(factor(dose)), data=failuredf, type="p", col=c("darkgreen","blue","darkorange","red"), pch=16, cex=1.5)
points(c(0.95,1.05),c(0,0),col="purple", pch=2)
axis(1, at=c(1,2,3,4), labels=c("0.003", "3.35", "8.34", "65.84"), font=1, cex.axis=1.5, line=5)
mtext(expression(Mean~egg~mg/kg~Sigma*PFAS), side=1, line=8, font=1, cex=1.5)

Interpolate adverse increase in probability of nest failure using Bernoulli GLM

Using the posterior draws, find the doses bracketing 95% probability of observing that amount of nest failure.

Background probability of having zero hatched eggs

dbinom(1,1,prob=contb)
## [1] 0.3577885

0.2 added risk of having zero hatched eggs

dbinom(1,1,prob=contb)+0.2
## [1] 0.5577885

Highest concentration where probability of having zero eggs is <0.28

i.e. “safe” concentration

### do prediction interpolation for having zero

alt.conc.pred <- seq(from=0.0001,to=3, length.out=1000)
pred3 <- array(NA,dim=c(length(alt.conc.pred),12000))
for(i in 1:12000){
  pred3[,i] <- plogis(out2$sims.list$alpha[i]+out2$sims.list$beta[i]*alt.conc.pred)
}

pm3 <- apply(pred3,1, mean)
pm3l <- apply(pred3,1, quantile, probs=0.975)
pm3u <- apply(pred3,1, quantile, probs=0.025)

prob2 <- apply(pred3, 1, function(x) mean((x-1)<0))

dprob02 <- apply(pred3,1,function(x) mean(dbinom(1,1,prob=x)))
dprob02min <- apply(pred3,1,function(x) quantile(dbinom(1,1,prob=x), probs=0.05))
dprob02max <- apply(pred3,1,function(x) quantile(dbinom(1,1,prob=x), probs=0.95))

#plot(dprob0~alt.conc.pred, ylim=c(0,1))
#points(dprob0min~alt.conc.pred, col="darkgray")
#points(dprob0max~alt.conc.pred, col="darkgray")


mintwentythreshold2 <- max(alt.conc.pred[dprob02min<0.5579766])
maxtwentythreshold2 <- max(alt.conc.pred[dprob02max<0.5579766])
meantwentythreshold2 <- max(alt.conc.pred[dprob02<0.5579766])
mintwentythreshold2
## [1] 2.915919
meantwentythreshold2
## [1] 0.8919622
maxtwentythreshold2
## [1] 0.3574454
par(mai=c(1.2,1.2,0.1,0.75))
plot(dprob02~alt.conc.pred, log="", ylim=c(0,1), type="l", bty="n", xlim=c(-0.25,3),
     ylab="Probability of nest failure", xlab=expression(paste("Adult daily dose ", Sigma,"PFAS mg/kg")), las=1,
     font=1, font.lab=1, pch=16, cex=2, lwd=2, cex.lab=1.5, cex.axis=1.5)
points(dprob02min~alt.conc.pred, type="l", lty=2, col="darkgray", lwd=2)
points(dprob02max~alt.conc.pred, type="l", lty=2, col="darkgray", lwd=2)
abline(h=c(0,1))
text(-0.35,dbinom(1,1,prob=contb),"0.36", pos=4, col="darkgreen")
text(-0.35,dbinom(1,1,prob=contb)+0.2,"0.56", pos=4, col="red")
segments(0,dbinom(1,1,prob=contb)+0.2,3,dbinom(1,1,prob=contb)+0.2, col="red")
segments(0.3514396,0.56,0.3514396,0.66, col="black")
text(0.3514396,0.66,"0.35 mg/kg", pos=3, col="black")
segments(3,0.56,3,0.26, col="black")
text(2.915919,0.26,"2.92 mg/kg", pos=1, col="black", xpd=NA)
segments(0.8919622,0.56,0.8919622,0.36, col="black")
text(0.8919622,0.36,"0.89 mg/kg", pos=1, col="black", xpd=NA)

Stochastic population trajectories

Simple model diagram

mermaid("
  graph RL
    A(Adult);
    J(Juvenile);
    I(Immigration);
    
    A--Fecundity-->J;
    A--Adult Survival-->A;
    J--Juvenile Survival-->A;
    I-->A;
", 
width=500, height=500)

Build distributions for demographic rates

Survival and immigration rates from McClure et al. 2021. McClure CJW et al. 2021. Demography of a widespread raptor across disparate regions. Ibis. 163(2):658–670 https://doi.org/10.1111/ibi.12916

Juvenile survival

juvsurvdist <- c(
  rnorm(1000, mean=0.13, sd=0.06),
  rnorm(1000, mean=0.15, sd=0.05),
  rnorm(1000, mean=0.09, sd=0.03),
  rnorm(1000, mean=0.08, sd=0.06)
)
juvsurvdist <- juvsurvdist[!juvsurvdist<0]
par(mfrow=c(1,2),mai=c(0.8,0.8,0.1,0.1))
hist(juvsurvdist, main="")
plot(density(juvsurvdist), main="",bty="n")

par(mfrow=c(1,1),mai=c(1,1,0.5,0.5))
summary(juvsurvdist)
##      Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
## 0.0003585 0.0756261 0.1106364 0.1159136 0.1525845 0.3493614
sd(juvsurvdist)
## [1] 0.05639346

Juvenile survival variability

Across the populations.

sd(c(0.13, 0.15, 0.09, 0.08))
## [1] 0.03304038

Adult survival

adtsurvdist <- c(
  rnorm(1000, mean=0.50, sd=0.03),
  rnorm(1000, mean=0.48, sd=0.03),
  rnorm(1000, mean=0.55, sd=0.03),
  rnorm(1000, mean=0.56, sd=0.08)
)
#adtsurvdist <- adtsurvdist[adtsurvdist>0]
par(mfrow=c(1,2),mai=c(0.8,0.8,0.1,0.1))
hist(adtsurvdist, main="")
plot(density(adtsurvdist), main="",bty="n")

par(mfrow=c(1,1),mai=c(1,1,0.5,0.5))
summary(adtsurvdist)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.3272  0.4826  0.5151  0.5229  0.5548  0.7859
sd(adtsurvdist)
## [1] 0.05953504

Adult survival variability

sd(c(0.50, 0.48, 0.55, 0.56))
## [1] 0.0386221

Immigration

immidist <- c(
  rnorm(1000, mean=0.21, sd=0.06),
  rnorm(1000, mean=0.21, sd=0.05),
  rnorm(1000, mean=0.15, sd=0.04),
  rnorm(1000, mean=0.20, sd=0.09)
)
immidist <- immidist[!immidist<0]
par(mfrow=c(1,2),mai=c(0.8,0.8,0.1,0.1))
hist(immidist, main="")
plot(density(immidist), main="",bty="n")

par(mfrow=c(1,1),mai=c(1,1,0.5,0.5))
summary(immidist)
##     Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
## 0.001566 0.148561 0.191600 0.194103 0.236840 0.474021
sd(immidist)
## [1] 0.06687488

Immigration variability

sd(c(0.21, 0.21, 0.15, 0.20))
## [1] 0.02872281

Fecundity

fecunddist <- c(
  rnorm(1000, mean=1.55, sd=0.13),
  rnorm(1000, mean=1.36, sd=0.05),
  rnorm(1000, mean=1.38, sd=0.06),
  rnorm(1000, mean=1.32, sd=0.13)
)
#fecunddist <- fecunddist[!fecunddist<0]
par(mfrow=c(1,2),mai=c(0.8,0.8,0.1,0.1))
hist(fecunddist, main="")
plot(density(fecunddist), main="",bty="n")

par(mfrow=c(1,1),mai=c(1,1,0.5,0.5))
summary(fecunddist)
##    Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
##  0.9304  1.3272  1.3820  1.4032  1.4625  1.9546
sd(fecunddist)
## [1] 0.1328875

Fecundity variability

sd(c(1.55, 1.36, 1.38, 1.32))
## [1] 0.1014479

trial run using Chapter.Section 3.3 from IPM book

3.3 Classical analysis of a matrix population model

3.3.

3.3.5 Analysis of a matrix population model with different sources of stochasticity and parameter uncertainty

See https://github.com/mikemeredith/IPM_code/blob/main/IPM_03/IPM_03.3.5.R

Code has been modified so “temporal” stochasticity is replaced with “population” stochasticity based on the 4 populations in Mcclure et al. 2021.

R stuff to make it happen, borrowed from IPM book package

# https://github.com/kenkellner/IPMbook/blob/main/R/stopifnot.R

stopifnotProbability <- function(arg, allowNA=FALSE) {
  name <- deparse(substitute(arg))
  if(allowNA && all(is.na(arg))) {  # An all-NA vector is logical, but ok.
    # do nothing
  } else {
    if(!allowNA && any(is.na(arg)))
      stop("Argument '", name, "' must not contain NA or NaN.", call.=FALSE)
    if(!is.numeric(arg))
      stop("Argument '", name, "' must be numeric.", call.=FALSE)
    if(any(arg < 0 | arg > 1, na.rm=TRUE)) {
      if(allowNA) {
        stop("Argument '", name, "' must be a probability between 0 and 1, or NA.", call.=FALSE)
      } else {
        stop("Argument '", name, "' must be a probability between 0 and 1.", call.=FALSE)
      }
    }
  }
}

stopifNegative <- function(arg, allowNA=FALSE, allowZero=TRUE) {
  name <- deparse(substitute(arg))
  if(allowNA && all(is.na(arg))) {  # An all-NA vector is logical, but ok.
    # do nothing
  } else {
    if(!allowNA && any(is.na(arg)))
      stop("Argument '", name, "' must not contain NA or NaN.", call.=FALSE)
    if(!is.numeric(arg))
      stop("Argument '", name, "' must be numeric.", call.=FALSE)
    if(allowZero) {
      if(any(arg < 0, na.rm=TRUE)) {
        if(allowNA) {
          stop("Argument '", name, "' must be non-negative, or NA.", call.=FALSE)
        } else {
          stop("Argument '", name, "' must be non-negative.", call.=FALSE)
        }
      }
    } else {
      if(any(arg <= 0, na.rm=TRUE)) {
        if(allowNA) {
          stop("Argument '", name, "' must be greater than 0, or NA.", call.=FALSE)
        } else {
          stop("Argument '", name, "' must be greater than 0.", call.=FALSE)
        }
      }
    }
  }
}

# https://github.com/kenkellner/IPMbook/blob/main/R/stopifnot.R

# https://github.com/kenkellner/IPMbook/blob/main/R/BetaDist.R

getBeta2Par <- function(mean, sd) {
  stopifnotProbability(mean, allowNA=FALSE)
  stopifNegative(sd, allowNA=FALSE, allowZero=FALSE)

  nu <- mean * (1-mean) / sd^2 - 1
  if(any(nu <= 0)) {
    warning("sd is too large; some shape parameters will be NA.", call.=FALSE)
    nu[nu <= 0] <- NA
  }
  alpha <- mean * nu
  beta <- (1-mean) * nu
  cbind(shape1=alpha, shape2=beta)
}

dbeta2 <- function(x, mean, sd) {
  shapes <- getBeta2Par(mean,sd)
  return(dbeta(x, shapes[,1], shapes[,2]))
}

pbeta2 <- function(q, mean, sd, lower.tail=TRUE, log.p=FALSE) {
  shapes <- getBeta2Par(mean,sd)
  return(pbeta(q, shapes[,1], shapes[,2], lower.tail=lower.tail, log.p=log.p))
}
qbeta2 <- function(p, mean, sd, lower.tail=TRUE, log.p=FALSE) {
  shapes <- getBeta2Par(mean,sd)
  return(qbeta(p, shapes[,1], shapes[,2], lower.tail=lower.tail, log.p=log.p))
}

rbeta2 <- function(n, mean, sd) {
  shapes <- getBeta2Par(mean,sd)
  return(rbeta(n, shapes[,1], shapes[,2]))
}

# https://github.com/kenkellner/IPMbook/blob/main/R/BetaDist.R

Actual simulations

# https://github.com/mikemeredith/IPM_code/blob/main/IPM_03/IPM_03.3.5.R

# 3.3 Classical analysis of a matrix population model
# ===================================================

# 3.3.5 Analysis of a matrix population model with different sources of
#       stochasticity and parameter uncertainty
# ---------------------------------------------------------------------

# Define mean, measurement error and temporal variability of the demographic parameters
mean.sj <- 0.1163615          # Mean value of juv. survival
sd.sj.e <- 0.0554588        # Uncertainty of mean juv. survival as SD on natural scale
sd.sj.t <- plogis(0.03304038)         # population variability of juv. survival as SD on logit scale # Andrew, this might have to be plogis(0.03304038), but not sure, check the text.
mean.sa <- 0.5222         # Mean value of ad. survival
sd.sa.e <- 0.05769693        # Uncertainty of mean ad. survival as SD on natural scale
sd.sa.t <- plogis(0.0386221)         # Temporal variability of ad. survival as SD on logit scale
mean.f1 <- 1.4035          # Mean value of productivity of 1y females
sd.f1.e <- 0.1326032         # Uncertainty of mean productivity as SD on natural scale
sd.f1.t <- 0.1014479          # Temporal variability of productivity as SD on natural scale
mean.fa <- 1.4035          # Mean value of productivity of adult females
sd.fa.e <- 0.1326032         # Uncertainty of mean productivity as SD on natural scale
sd.fa.t <- 0.101          # Temporal variability of productivity as SD on natural scale
mean.imm <- 0.192587      # Mean value of adult immigration  
sd.imm.e <- 0.06674809    # Uncertainty of mean adult immigration as SD on natural scale
sd.imm.t <- 0.02872281    # population variability of adult immigration as SD on natrual scale

# Define the number of years with predictions and the Monte Carlo setting
T <- 10                # Number of years (projection time frame)
nsim <- 10000          # Number of replicate populations simulated

# Define population matrix and initial stage-specific population sizes
N <- array(NA, dim=c(2, T+1, nsim))
N[,1,] <- c(3,1)
r <- matrix(NA, nrow=T, ncol=nsim)
alive <- matrix(NA, nrow=T, ncol=nsim)
mean.r <- numeric(nsim)

# Project population
for (s in 1:nsim){ # Loop over replicate populations
  #if(s %% 100 == 0) {cat(paste("*** Simrep", s, "***\n")) }   # Counter
  # Generate a mean of the demographic rates (subject to measurement error)
  msj <- rbeta2(1, mean.sj, sd.sj.e)
  msa <- rbeta2(1, mean.sa, sd.sa.e)
  mf1 <- rnorm(1, mean.f1, sd.f1.e)
  mfa <- rnorm(1, mean.fa, sd.fa.e)
  mia <- rnorm(1, mean.imm, sd.imm.e)

  # Generate annual demographic rates (subject to temporal variability)
  sj <- plogis(rnorm(T, qlogis(msj), sd.sj.t))
  sa <- plogis(rnorm(T, qlogis(msa), sd.sa.t))
  f1 <- pmax(0, rnorm(T, mf1, sd.f1.t))                       # Avoids negative values
  fa <- pmax(0, rnorm(T, mfa, sd.fa.t))                       # Ditto
  ia <- pmax(0, rnorm(T, mia, sd.imm.t))                       # Ditto

  # Project population (include demographic stochasticity)
  for (t in 1:T){                                             # Loop over years
    N[1,t+1,s] <- rpois(1, sj[t] * (f1[t] * N[1,t,s] + fa[t] * N[2,t,s]))
    N[2,t+1,s] <- rbinom(1, sum(N[,t,s]), sa[t])+rpois(1,ia)
    if (sum(N[,t+1,s]) == 0) break
    #r[t,s] <- log(sum(N[,t+1,s])) - log(sum(N[,t,s]))
    alive[t,s] <- t
  } #t
  #mean.r[s] <- mean(r[min(alive[,s], na.rm=TRUE):max(alive[,s], na.rm=TRUE),s])
} 

#mean(mean.r)

#sd(mean.r)


not.extinct <- which(!is.na(alive[T,]))
mean(mean.r[not.extinct])
## [1] 0
sd(mean.r[not.extinct])
## [1] 0
# Extinction probability (after T years)
sum(is.na(alive[T,])) / nsim
## [1] 0.8031
rowSums(is.na(alive)) / nsim
##  [1] 0.0342 0.1379 0.2686 0.3941 0.5065 0.5914 0.6652 0.7232 0.7672 0.8031
df <- data.frame(
  totalcount=c(colSums(N[,,1:nsim])),
  time=rep(c(0:T),nsim),
  simnumber=gl(nsim, T+1)
)


# plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3)
# boxplot(c(colSums(N[,,1:nsim]))~factor(rep(c(0:T),nsim)))
 bxpobj<-boxplot(c(colSums(N[,,1:nsim]))~factor(rep(c(0:T),nsim)), plot=F)
# plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3)
# points(bxpobj$stats[3,]~c(0:T), type="l", col="red", lwd=2)
# 
# par(mai=c(1,1,0.1,1))
# plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3)
# points(bxpobj$stats[3,]~c(0:T), type="b", col="blue", lwd=2, pch=16)
# par(new=T)
# plot(c(rowSums(is.na(alive))/nsim)~c(1:T), type="b", col="red", bty="n", xlab="", ylab="", axes=F, ylim=c(0,1), xlim=c(0,T), lwd=2, pch=16)
# axis(side=4, at=pretty(range(c(0,1))))
# mtext("probability of extinction", side=4, line=3)

par(mai=c(1,1,0.1,1))
plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3, xlab="years of simulation", ylab="estimated population size")
points(bxpobj$stats[3,]~c(0:T), type="b", col="blue", lwd=2, pch=16)
par(new=T)
plot(c(rowSums(is.na(alive))/nsim)~c(1:T), type="b", col="red", bty="n", xlab="", ylab="", axes=F, ylim=c(0,1), xlim=c(0,T), lwd=2, pch=16)
axis(side=4, at=pretty(range(c(0,1))))
mtext("proportion of simulations reached N=0", side=4, line=3, col="red")

ggplot()+
 geom_line(data=df, aes(x=time, y=totalcount, group=simnumber), linewidth=1, color="gray", alpha=0.8) +
 geom_line(aes(x=c(0:T), y=bxpobj$stats[3,]), color="blue", linewidth=3)+
 #geom_line(aes(x=c(1:T), y=c(rowSums(is.na(alive))/nsim)), col="red", linewidth=2)+
 geom_label(aes(x=c(1:T), y=0, label=round(c(rowSums(is.na(alive))/nsim), 2)), color="red")+
 scale_x_continuous(breaks=c(1:10))+scale_y_continuous(breaks=seq(0,50, by=2))+
 theme_classic(base_size=22) +
 labs(x="Years of simulated population size and\nproportion of simulations with N=0", y="Total simulated population count")
## Warning: Removed 40883 rows containing missing values or values outside the scale range
## (`geom_line()`).

ggplot()+
  geom_jitter(data=df, aes(x=time, y=totalcount, group=simnumber), shape=".", width=0.3, height=0.3) +
  geom_line(aes(x=c(0:T), y=bxpobj$stats[3,]), color="blue", linewidth=3)+
  #geom_line(aes(x=c(1:T), y=c(rowSums(is.na(alive))/nsim)), col="red", linewidth=2)+
  geom_label(aes(x=c(1:T), y=-0.5, label=round(c(rowSums(is.na(alive))/nsim), 2)), color="red")+
  scale_x_continuous(breaks=c(1:10))+scale_y_continuous(breaks=seq(0,50, by=2))+
  theme_classic(base_size=22)+
  labs(x="Years of simulated population size and\nproportion of simulations with N=0", y="Total simulated population count")
## Warning: Removed 40883 rows containing missing values or values outside the scale range
## (`geom_point()`).

# ggplot()+
#   geom_hex(data=df, aes(x=time, y=totalcount, group=simnumber), bins=10) +
#   geom_line(aes(x=c(0:T), y=bxpobj$stats[3,]), color="blue", linewidth=3)+
#   #geom_line(aes(x=c(1:T), y=c(rowSums(is.na(alive))/nsim)), col="red", linewidth=2)+
#   geom_label(aes(x=c(1:T), y=-0.5, label=round(c(rowSums(is.na(alive))/nsim), 2)), color="red")+
#   scale_x_continuous(breaks=c(1:10))+scale_y_continuous(breaks=seq(0,50, by=2))+
#   theme_classic(base_size=22)+
#   labs(x="Years of simulated population size and\nproportion of simulations with N=0", y="Total simulated population count")


# ~~~~ Plot graph with population growth rates (Fig. 3.15)  ~~~~
# op <- par(mar=c(4, 4, 2, 1), las=1, cex=1.1, "mfrow")
# layout(matrix(c(1, 1, 2, 3), 2, 2, byrow=TRUE), widths=c(1, 1), heights=c(1, 1), TRUE)
# plot(r[,1], type="l", lwd=0.5, ylab="Annual population growth rate", xlab="Time",
#     ylim=range(r[which(!is.na(alive))]), col="lightgrey", axes=FALSE)
# axis(1); axis(2)
# for (s in 2:nsim){
#   lines(r[!is.na(alive[,s]),s], lwd=0.5, col="lightgrey")
# }
# lines(apply(r, 1, mean, na.rm=TRUE), lwd=1.5)
# mtext("A", at=0, cex=1.5)
# a <- hist(mean.r, nclass=50, col="dodgerblue", main="",
#     xlab="Population growth rate", axes=FALSE) #xlim=c(-2.5, 0.1), 
# axis(1)
# axis(2, at=c(0, 5000, 10000, 15000, 20000, 25000, 30000), labels=c(0, 5, 10, 15, 20, 25, 30))
# mtext("B", at=a$mids[1], cex=1.5)
# a <- hist(mean.r[not.extinct], nclass=25, col="dodgerblue", main="",
#     xlab="Population growth rate", axes=FALSE)
# axis(1)
# axis(2, at=c(0, 2000, 4000, 6000, 8000, 10000), labels=c(0, 2, 4, 6, 8, 10))
# mtext("C", at=a$mids[1], cex=1.5)
# par(op)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# https://github.com/mikemeredith/IPM_code/blob/main/IPM_03/IPM_03.3.5.R

Control Treatment simulations

# https://github.com/mikemeredith/IPM_code/blob/main/IPM_03/IPM_03.3.5.R

# 3.3 Classical analysis of a matrix population model
# ===================================================

# 3.3.5 Analysis of a matrix population model with different sources of
#       stochasticity and parameter uncertainty
# ---------------------------------------------------------------------

# Define mean, measurement error and temporal variability of the demographic parameters
mean.sj <- 0.1163615          # Mean value of juv. survival
sd.sj.e <- 0.0554588        # Uncertainty of mean juv. survival as SD on natural scale
sd.sj.t <- plogis(0.03304038)         # population variability of juv. survival as SD on logit scale # Andrew, this might have to be plogis(0.03304038), but not sure, check the text.
mean.sa <- 0.5222         # Mean value of ad. survival
sd.sa.e <- 0.05769693        # Uncertainty of mean ad. survival as SD on natural scale
sd.sa.t <- plogis(0.0386221)         # Temporal variability of ad. survival as SD on logit scale
mean.f1 <- 2.575          # Mean value of productivity of 1y females
sd.f1.e <- 0.1326032         # Uncertainty of mean productivity as SD on natural scale
sd.f1.t <- 0.1014479          # Temporal variability of productivity as SD on natural scale
mean.fa <- 2.575          # Mean value of productivity of adult females
sd.fa.e <- 0.1326032         # Uncertainty of mean productivity as SD on natural scale
sd.fa.t <- 0.101          # Temporal variability of productivity as SD on natural scale
mean.imm <- 0.192587      # Mean value of adult immigration  
sd.imm.e <- 0.06674809    # Uncertainty of mean adult immigration as SD on natural scale
sd.imm.t <- 0.02872281    # population variability of adult immigration as SD on natrual scale

# Define the number of years with predictions and the Monte Carlo setting
T <- 10                # Number of years (projection time frame)
nsim <- 10000          # Number of replicate populations simulated

# Define population matrix and initial stage-specific population sizes
N <- array(NA, dim=c(2, T+1, nsim))
N[,1,] <- c(3,1)
r <- matrix(NA, nrow=T, ncol=nsim)
alive <- matrix(NA, nrow=T, ncol=nsim)
mean.r <- numeric(nsim)

# Project population
for (s in 1:nsim){ # Loop over replicate populations
  #if(s %% 100 == 0) {cat(paste("*** Simrep", s, "***\n")) }   # Counter
  # Generate a mean of the demographic rates (subject to measurement error)
  msj <- rbeta2(1, mean.sj, sd.sj.e)
  msa <- rbeta2(1, mean.sa, sd.sa.e)
  mf1 <- rnorm(1, mean.f1, sd.f1.e)
  mfa <- rnorm(1, mean.fa, sd.fa.e)
  mia <- rnorm(1, mean.imm, sd.imm.e)

  # Generate annual demographic rates (subject to temporal variability)
  sj <- plogis(rnorm(T, qlogis(msj), sd.sj.t))
  sa <- plogis(rnorm(T, qlogis(msa), sd.sa.t))
  f1 <- pmax(0, rnorm(T, mf1, sd.f1.t))                       # Avoids negative values
  fa <- pmax(0, rnorm(T, mfa, sd.fa.t))                       # Ditto
  ia <- pmax(0, rnorm(T, mia, sd.imm.t))                       # Ditto

  # Project population (include demographic stochasticity)
  for (t in 1:T){                                             # Loop over years
    N[1,t+1,s] <- rpois(1, sj[t] * (f1[t] * N[1,t,s] + fa[t] * N[2,t,s]))
    N[2,t+1,s] <- rbinom(1, sum(N[,t,s]), sa[t])+rpois(1,ia)
    if (sum(N[,t+1,s]) == 0) break
    #r[t,s] <- log(sum(N[,t+1,s])) - log(sum(N[,t,s]))
    alive[t,s] <- t
  } #t
  #mean.r[s] <- mean(r[min(alive[,s], na.rm=TRUE):max(alive[,s], na.rm=TRUE),s])
} 

#mean(mean.r)

#sd(mean.r)


not.extinct <- which(!is.na(alive[T,]))
mean(mean.r[not.extinct])
## [1] 0
sd(mean.r[not.extinct])
## [1] 0
# Extinction probability (after T years)
sum(is.na(alive[T,])) / nsim
## [1] 0.5943
rowSums(is.na(alive)) / nsim
##  [1] 0.0254 0.0902 0.1752 0.2637 0.3443 0.4097 0.4697 0.5164 0.5589 0.5943
df <- data.frame(
  totalcount=c(colSums(N[,,1:nsim])),
  time=rep(c(0:T),nsim),
  simnumber=gl(nsim, T+1)
)


# plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3)
# boxplot(c(colSums(N[,,1:nsim]))~factor(rep(c(0:T),nsim)))
 bxpobj<-boxplot(c(colSums(N[,,1:nsim]))~factor(rep(c(0:T),nsim)), plot=F)
# plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3)
# points(bxpobj$stats[3,]~c(0:T), type="l", col="red", lwd=2)
# 
# par(mai=c(1,1,0.1,1))
# plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3)
# points(bxpobj$stats[3,]~c(0:T), type="b", col="blue", lwd=2, pch=16)
# par(new=T)
# plot(c(rowSums(is.na(alive))/nsim)~c(1:T), type="b", col="red", bty="n", xlab="", ylab="", axes=F, ylim=c(0,1), xlim=c(0,T), lwd=2, pch=16)
# axis(side=4, at=pretty(range(c(0,1))))
# mtext("probability of extinction", side=4, line=3)

par(mai=c(1,1,0.1,1))
plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3, xlab="years of simulation", ylab="estimated population size")
points(bxpobj$stats[3,]~c(0:T), type="b", col="blue", lwd=2, pch=16)
par(new=T)
plot(c(rowSums(is.na(alive))/nsim)~c(1:T), type="b", col="red", bty="n", xlab="", ylab="", axes=F, ylim=c(0,1), xlim=c(0,T), lwd=2, pch=16)
axis(side=4, at=pretty(range(c(0,1))))
mtext("proportion of simulations reached N=0", side=4, line=3, col="red")

ggplot()+
 geom_line(data=df, aes(x=time, y=totalcount, group=simnumber), linewidth=1, color="gray", alpha=0.8) +
 geom_line(aes(x=c(0:T), y=bxpobj$stats[3,]), color="blue", linewidth=3)+
 #geom_line(aes(x=c(1:T), y=c(rowSums(is.na(alive))/nsim)), col="red", linewidth=2)+
 geom_label(aes(x=c(1:T), y=0, label=round(c(rowSums(is.na(alive))/nsim), 2)), color="red")+
 scale_x_continuous(breaks=c(1:10))+scale_y_continuous(breaks=seq(0,50, by=2))+
 theme_classic(base_size=22) +
 labs(x="Years of simulated population size and\nproportion of simulations with N=0", y="Total simulated population count")
## Warning: Removed 28535 rows containing missing values or values outside the scale range
## (`geom_line()`).

ggplot()+
  geom_jitter(data=df, aes(x=time, y=totalcount, group=simnumber), shape=".", width=0.3, height=0.3) +
  geom_line(aes(x=c(0:T), y=bxpobj$stats[3,]), color="blue", linewidth=3)+
  #geom_line(aes(x=c(1:T), y=c(rowSums(is.na(alive))/nsim)), col="red", linewidth=2)+
  geom_label(aes(x=c(1:T), y=-0.5, label=round(c(rowSums(is.na(alive))/nsim), 2)), color="red")+
  scale_x_continuous(breaks=c(1:10))+scale_y_continuous(breaks=seq(0,50, by=2))+
  theme_classic(base_size=22)+
  labs(x="Years of simulated population size and\nproportion of simulations with N=0", y="Total simulated population count")
## Warning: Removed 28535 rows containing missing values or values outside the scale range
## (`geom_point()`).

# ggplot()+
#   geom_hex(data=df, aes(x=time, y=totalcount, group=simnumber), bins=10) +
#   geom_line(aes(x=c(0:T), y=bxpobj$stats[3,]), color="blue", linewidth=3)+
#   #geom_line(aes(x=c(1:T), y=c(rowSums(is.na(alive))/nsim)), col="red", linewidth=2)+
#   geom_label(aes(x=c(1:T), y=-0.5, label=round(c(rowSums(is.na(alive))/nsim), 2)), color="red")+
#   scale_x_continuous(breaks=c(1:10))+scale_y_continuous(breaks=seq(0,50, by=2))+
#   theme_classic(base_size=22)+
#   labs(x="Years of simulated population size and\nproportion of simulations with N=0", y="Total simulated population count")


# ~~~~ Plot graph with population growth rates (Fig. 3.15)  ~~~~
# op <- par(mar=c(4, 4, 2, 1), las=1, cex=1.1, "mfrow")
# layout(matrix(c(1, 1, 2, 3), 2, 2, byrow=TRUE), widths=c(1, 1), heights=c(1, 1), TRUE)
# plot(r[,1], type="l", lwd=0.5, ylab="Annual population growth rate", xlab="Time",
#     ylim=range(r[which(!is.na(alive))]), col="lightgrey", axes=FALSE)
# axis(1); axis(2)
# for (s in 2:nsim){
#   lines(r[!is.na(alive[,s]),s], lwd=0.5, col="lightgrey")
# }
# lines(apply(r, 1, mean, na.rm=TRUE), lwd=1.5)
# mtext("A", at=0, cex=1.5)
# a <- hist(mean.r, nclass=50, col="dodgerblue", main="",
#     xlab="Population growth rate", axes=FALSE) #xlim=c(-2.5, 0.1), 
# axis(1)
# axis(2, at=c(0, 5000, 10000, 15000, 20000, 25000, 30000), labels=c(0, 5, 10, 15, 20, 25, 30))
# mtext("B", at=a$mids[1], cex=1.5)
# a <- hist(mean.r[not.extinct], nclass=25, col="dodgerblue", main="",
#     xlab="Population growth rate", axes=FALSE)
# axis(1)
# axis(2, at=c(0, 2000, 4000, 6000, 8000, 10000), labels=c(0, 2, 4, 6, 8, 10))
# mtext("C", at=a$mids[1], cex=1.5)
# par(op)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# https://github.com/mikemeredith/IPM_code/blob/main/IPM_03/IPM_03.3.5.R

Low Treatment simulations

# https://github.com/mikemeredith/IPM_code/blob/main/IPM_03/IPM_03.3.5.R

# 3.3 Classical analysis of a matrix population model
# ===================================================

# 3.3.5 Analysis of a matrix population model with different sources of
#       stochasticity and parameter uncertainty
# ---------------------------------------------------------------------

# Define mean, measurement error and temporal variability of the demographic parameters
mean.sj <- 0.1163615          # Mean value of juv. survival
sd.sj.e <- 0.0554588        # Uncertainty of mean juv. survival as SD on natural scale
sd.sj.t <- plogis(0.03304038)         # population variability of juv. survival as SD on logit scale # Andrew, this might have to be plogis(0.03304038), but not sure, check the text.
mean.sa <- 0.5222         # Mean value of ad. survival
sd.sa.e <- 0.05769693        # Uncertainty of mean ad. survival as SD on natural scale
sd.sa.t <- plogis(0.0386221)         # Temporal variability of ad. survival as SD on logit scale
mean.f1 <- 2.264          # Mean value of productivity of 1y females
sd.f1.e <- 0.1326032         # Uncertainty of mean productivity as SD on natural scale
sd.f1.t <- 0.1014479          # Temporal variability of productivity as SD on natural scale
mean.fa <- 2.264          # Mean value of productivity of adult females
sd.fa.e <- 0.1326032         # Uncertainty of mean productivity as SD on natural scale
sd.fa.t <- 0.101          # Temporal variability of productivity as SD on natural scale
mean.imm <- 0.192587      # Mean value of adult immigration  
sd.imm.e <- 0.06674809    # Uncertainty of mean adult immigration as SD on natural scale
sd.imm.t <- 0.02872281    # population variability of adult immigration as SD on natrual scale

# Define the number of years with predictions and the Monte Carlo setting
T <- 10                # Number of years (projection time frame)
nsim <- 10000          # Number of replicate populations simulated

# Define population matrix and initial stage-specific population sizes
N <- array(NA, dim=c(2, T+1, nsim))
N[,1,] <- c(3,1)
r <- matrix(NA, nrow=T, ncol=nsim)
alive <- matrix(NA, nrow=T, ncol=nsim)
mean.r <- numeric(nsim)

# Project population
for (s in 1:nsim){ # Loop over replicate populations
  #if(s %% 100 == 0) {cat(paste("*** Simrep", s, "***\n")) }   # Counter
  # Generate a mean of the demographic rates (subject to measurement error)
  msj <- rbeta2(1, mean.sj, sd.sj.e)
  msa <- rbeta2(1, mean.sa, sd.sa.e)
  mf1 <- rnorm(1, mean.f1, sd.f1.e)
  mfa <- rnorm(1, mean.fa, sd.fa.e)
  mia <- rnorm(1, mean.imm, sd.imm.e)

  # Generate annual demographic rates (subject to temporal variability)
  sj <- plogis(rnorm(T, qlogis(msj), sd.sj.t))
  sa <- plogis(rnorm(T, qlogis(msa), sd.sa.t))
  f1 <- pmax(0, rnorm(T, mf1, sd.f1.t))                       # Avoids negative values
  fa <- pmax(0, rnorm(T, mfa, sd.fa.t))                       # Ditto
  ia <- pmax(0, rnorm(T, mia, sd.imm.t))                       # Ditto

  # Project population (include demographic stochasticity)
  for (t in 1:T){                                             # Loop over years
    N[1,t+1,s] <- rpois(1, sj[t] * (f1[t] * N[1,t,s] + fa[t] * N[2,t,s]))
    N[2,t+1,s] <- rbinom(1, sum(N[,t,s]), sa[t])+rpois(1,ia)
    if (sum(N[,t+1,s]) == 0) break
    #r[t,s] <- log(sum(N[,t+1,s])) - log(sum(N[,t,s]))
    alive[t,s] <- t
  } #t
  #mean.r[s] <- mean(r[min(alive[,s], na.rm=TRUE):max(alive[,s], na.rm=TRUE),s])
} 

#mean(mean.r)

#sd(mean.r)


not.extinct <- which(!is.na(alive[T,]))
mean(mean.r[not.extinct])
## [1] 0
sd(mean.r[not.extinct])
## [1] 0
# Extinction probability (after T years)
sum(is.na(alive[T,])) / nsim
## [1] 0.6536
rowSums(is.na(alive)) / nsim
##  [1] 0.0270 0.1089 0.2069 0.2994 0.3825 0.4560 0.5194 0.5701 0.6143 0.6536
df <- data.frame(
  totalcount=c(colSums(N[,,1:nsim])),
  time=rep(c(0:T),nsim),
  simnumber=gl(nsim, T+1)
)


# plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3)
# boxplot(c(colSums(N[,,1:nsim]))~factor(rep(c(0:T),nsim)))
 bxpobj<-boxplot(c(colSums(N[,,1:nsim]))~factor(rep(c(0:T),nsim)), plot=F)
# plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3)
# points(bxpobj$stats[3,]~c(0:T), type="l", col="red", lwd=2)
# 
# par(mai=c(1,1,0.1,1))
# plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3)
# points(bxpobj$stats[3,]~c(0:T), type="b", col="blue", lwd=2, pch=16)
# par(new=T)
# plot(c(rowSums(is.na(alive))/nsim)~c(1:T), type="b", col="red", bty="n", xlab="", ylab="", axes=F, ylim=c(0,1), xlim=c(0,T), lwd=2, pch=16)
# axis(side=4, at=pretty(range(c(0,1))))
# mtext("probability of extinction", side=4, line=3)

par(mai=c(1,1,0.1,1))
plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3, xlab="years of simulation", ylab="estimated population size")
points(bxpobj$stats[3,]~c(0:T), type="b", col="blue", lwd=2, pch=16)
par(new=T)
plot(c(rowSums(is.na(alive))/nsim)~c(1:T), type="b", col="red", bty="n", xlab="", ylab="", axes=F, ylim=c(0,1), xlim=c(0,T), lwd=2, pch=16)
axis(side=4, at=pretty(range(c(0,1))))
mtext("proportion of simulations reached N=0", side=4, line=3, col="red")

ggplot()+
 geom_line(data=df, aes(x=time, y=totalcount, group=simnumber), linewidth=1, color="gray", alpha=0.8) +
 geom_line(aes(x=c(0:T), y=bxpobj$stats[3,]), color="blue", linewidth=3)+
 #geom_line(aes(x=c(1:T), y=c(rowSums(is.na(alive))/nsim)), col="red", linewidth=2)+
 geom_label(aes(x=c(1:T), y=0, label=round(c(rowSums(is.na(alive))/nsim), 2)), color="red")+
 scale_x_continuous(breaks=c(1:10))+scale_y_continuous(breaks=seq(0,50, by=2))+
 theme_classic(base_size=22) +
 labs(x="Years of simulated population size and\nproportion of simulations with N=0", y="Total simulated population count")
## Warning: Removed 31845 rows containing missing values or values outside the scale range
## (`geom_line()`).

ggplot()+
  geom_jitter(data=df, aes(x=time, y=totalcount, group=simnumber), shape=".", width=0.3, height=0.3) +
  geom_line(aes(x=c(0:T), y=bxpobj$stats[3,]), color="blue", linewidth=3)+
  #geom_line(aes(x=c(1:T), y=c(rowSums(is.na(alive))/nsim)), col="red", linewidth=2)+
  geom_label(aes(x=c(1:T), y=-0.5, label=round(c(rowSums(is.na(alive))/nsim), 2)), color="red")+
  scale_x_continuous(breaks=c(1:10))+scale_y_continuous(breaks=seq(0,50, by=2))+
  theme_classic(base_size=22)+
  labs(x="Years of simulated population size and\nproportion of simulations with N=0", y="Total simulated population count")
## Warning: Removed 31845 rows containing missing values or values outside the scale range
## (`geom_point()`).

# ggplot()+
#   geom_hex(data=df, aes(x=time, y=totalcount, group=simnumber), bins=10) +
#   geom_line(aes(x=c(0:T), y=bxpobj$stats[3,]), color="blue", linewidth=3)+
#   #geom_line(aes(x=c(1:T), y=c(rowSums(is.na(alive))/nsim)), col="red", linewidth=2)+
#   geom_label(aes(x=c(1:T), y=-0.5, label=round(c(rowSums(is.na(alive))/nsim), 2)), color="red")+
#   scale_x_continuous(breaks=c(1:10))+scale_y_continuous(breaks=seq(0,50, by=2))+
#   theme_classic(base_size=22)+
#   labs(x="Years of simulated population size and\nproportion of simulations with N=0", y="Total simulated population count")


# ~~~~ Plot graph with population growth rates (Fig. 3.15)  ~~~~
# op <- par(mar=c(4, 4, 2, 1), las=1, cex=1.1, "mfrow")
# layout(matrix(c(1, 1, 2, 3), 2, 2, byrow=TRUE), widths=c(1, 1), heights=c(1, 1), TRUE)
# plot(r[,1], type="l", lwd=0.5, ylab="Annual population growth rate", xlab="Time",
#     ylim=range(r[which(!is.na(alive))]), col="lightgrey", axes=FALSE)
# axis(1); axis(2)
# for (s in 2:nsim){
#   lines(r[!is.na(alive[,s]),s], lwd=0.5, col="lightgrey")
# }
# lines(apply(r, 1, mean, na.rm=TRUE), lwd=1.5)
# mtext("A", at=0, cex=1.5)
# a <- hist(mean.r, nclass=50, col="dodgerblue", main="",
#     xlab="Population growth rate", axes=FALSE) #xlim=c(-2.5, 0.1), 
# axis(1)
# axis(2, at=c(0, 5000, 10000, 15000, 20000, 25000, 30000), labels=c(0, 5, 10, 15, 20, 25, 30))
# mtext("B", at=a$mids[1], cex=1.5)
# a <- hist(mean.r[not.extinct], nclass=25, col="dodgerblue", main="",
#     xlab="Population growth rate", axes=FALSE)
# axis(1)
# axis(2, at=c(0, 2000, 4000, 6000, 8000, 10000), labels=c(0, 2, 4, 6, 8, 10))
# mtext("C", at=a$mids[1], cex=1.5)
# par(op)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# https://github.com/mikemeredith/IPM_code/blob/main/IPM_03/IPM_03.3.5.R

Medium Treatment simulations

# https://github.com/mikemeredith/IPM_code/blob/main/IPM_03/IPM_03.3.5.R

# 3.3 Classical analysis of a matrix population model
# ===================================================

# 3.3.5 Analysis of a matrix population model with different sources of
#       stochasticity and parameter uncertainty
# ---------------------------------------------------------------------

# Define mean, measurement error and temporal variability of the demographic parameters
mean.sj <- 0.1163615          # Mean value of juv. survival
sd.sj.e <- 0.0554588        # Uncertainty of mean juv. survival as SD on natural scale
sd.sj.t <- plogis(0.03304038)         # population variability of juv. survival as SD on logit scale # Andrew, this might have to be plogis(0.03304038), but not sure, check the text.
mean.sa <- 0.5222         # Mean value of ad. survival
sd.sa.e <- 0.05769693        # Uncertainty of mean ad. survival as SD on natural scale
sd.sa.t <- plogis(0.0386221)         # Temporal variability of ad. survival as SD on logit scale
mean.f1 <- 1.605          # Mean value of productivity of 1y females
sd.f1.e <- 0.1326032         # Uncertainty of mean productivity as SD on natural scale
sd.f1.t <- 0.1014479          # Temporal variability of productivity as SD on natural scale
mean.fa <- 1.605          # Mean value of productivity of adult females
sd.fa.e <- 0.1326032         # Uncertainty of mean productivity as SD on natural scale
sd.fa.t <- 0.101          # Temporal variability of productivity as SD on natural scale
mean.imm <- 0.192587      # Mean value of adult immigration  
sd.imm.e <- 0.06674809    # Uncertainty of mean adult immigration as SD on natural scale
sd.imm.t <- 0.02872281    # population variability of adult immigration as SD on natrual scale

# Define the number of years with predictions and the Monte Carlo setting
T <- 10                # Number of years (projection time frame)
nsim <- 10000          # Number of replicate populations simulated

# Define population matrix and initial stage-specific population sizes
N <- array(NA, dim=c(2, T+1, nsim))
N[,1,] <- c(3,1)
r <- matrix(NA, nrow=T, ncol=nsim)
alive <- matrix(NA, nrow=T, ncol=nsim)
mean.r <- numeric(nsim)

# Project population
for (s in 1:nsim){ # Loop over replicate populations
  #if(s %% 100 == 0) {cat(paste("*** Simrep", s, "***\n")) }   # Counter
  # Generate a mean of the demographic rates (subject to measurement error)
  msj <- rbeta2(1, mean.sj, sd.sj.e)
  msa <- rbeta2(1, mean.sa, sd.sa.e)
  mf1 <- rnorm(1, mean.f1, sd.f1.e)
  mfa <- rnorm(1, mean.fa, sd.fa.e)
  mia <- rnorm(1, mean.imm, sd.imm.e)

  # Generate annual demographic rates (subject to temporal variability)
  sj <- plogis(rnorm(T, qlogis(msj), sd.sj.t))
  sa <- plogis(rnorm(T, qlogis(msa), sd.sa.t))
  f1 <- pmax(0, rnorm(T, mf1, sd.f1.t))                       # Avoids negative values
  fa <- pmax(0, rnorm(T, mfa, sd.fa.t))                       # Ditto
  ia <- pmax(0, rnorm(T, mia, sd.imm.t))                       # Ditto

  # Project population (include demographic stochasticity)
  for (t in 1:T){                                             # Loop over years
    N[1,t+1,s] <- rpois(1, sj[t] * (f1[t] * N[1,t,s] + fa[t] * N[2,t,s]))
    N[2,t+1,s] <- rbinom(1, sum(N[,t,s]), sa[t])+rpois(1,ia)
    if (sum(N[,t+1,s]) == 0) break
    #r[t,s] <- log(sum(N[,t+1,s])) - log(sum(N[,t,s]))
    alive[t,s] <- t
  } #t
  #mean.r[s] <- mean(r[min(alive[,s], na.rm=TRUE):max(alive[,s], na.rm=TRUE),s])
} 

#mean(mean.r)

#sd(mean.r)


not.extinct <- which(!is.na(alive[T,]))
mean(mean.r[not.extinct])
## [1] 0
sd(mean.r[not.extinct])
## [1] 0
# Extinction probability (after T years)
sum(is.na(alive[T,])) / nsim
## [1] 0.7736
rowSums(is.na(alive)) / nsim
##  [1] 0.0300 0.1266 0.2507 0.3666 0.4616 0.5496 0.6284 0.6869 0.7358 0.7736
df <- data.frame(
  totalcount=c(colSums(N[,,1:nsim])),
  time=rep(c(0:T),nsim),
  simnumber=gl(nsim, T+1)
)


# plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3)
# boxplot(c(colSums(N[,,1:nsim]))~factor(rep(c(0:T),nsim)))
 bxpobj<-boxplot(c(colSums(N[,,1:nsim]))~factor(rep(c(0:T),nsim)), plot=F)
# plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3)
# points(bxpobj$stats[3,]~c(0:T), type="l", col="red", lwd=2)
# 
# par(mai=c(1,1,0.1,1))
# plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3)
# points(bxpobj$stats[3,]~c(0:T), type="b", col="blue", lwd=2, pch=16)
# par(new=T)
# plot(c(rowSums(is.na(alive))/nsim)~c(1:T), type="b", col="red", bty="n", xlab="", ylab="", axes=F, ylim=c(0,1), xlim=c(0,T), lwd=2, pch=16)
# axis(side=4, at=pretty(range(c(0,1))))
# mtext("probability of extinction", side=4, line=3)

par(mai=c(1,1,0.1,1))
plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3, xlab="years of simulation", ylab="estimated population size")
points(bxpobj$stats[3,]~c(0:T), type="b", col="blue", lwd=2, pch=16)
par(new=T)
plot(c(rowSums(is.na(alive))/nsim)~c(1:T), type="b", col="red", bty="n", xlab="", ylab="", axes=F, ylim=c(0,1), xlim=c(0,T), lwd=2, pch=16)
axis(side=4, at=pretty(range(c(0,1))))
mtext("proportion of simulations reached N=0", side=4, line=3, col="red")

ggplot()+
 geom_line(data=df, aes(x=time, y=totalcount, group=simnumber), linewidth=1, color="gray", alpha=0.8) +
 geom_line(aes(x=c(0:T), y=bxpobj$stats[3,]), color="blue", linewidth=3)+
 #geom_line(aes(x=c(1:T), y=c(rowSums(is.na(alive))/nsim)), col="red", linewidth=2)+
 geom_label(aes(x=c(1:T), y=0, label=round(c(rowSums(is.na(alive))/nsim), 2)), color="red")+
 scale_x_continuous(breaks=c(1:10))+scale_y_continuous(breaks=seq(0,50, by=2))+
 theme_classic(base_size=22) +
 labs(x="Years of simulated population size and\nproportion of simulations with N=0", y="Total simulated population count")
## Warning: Removed 38362 rows containing missing values or values outside the scale range
## (`geom_line()`).

ggplot()+
  geom_jitter(data=df, aes(x=time, y=totalcount, group=simnumber), shape=".", width=0.3, height=0.3) +
  geom_line(aes(x=c(0:T), y=bxpobj$stats[3,]), color="blue", linewidth=3)+
  #geom_line(aes(x=c(1:T), y=c(rowSums(is.na(alive))/nsim)), col="red", linewidth=2)+
  geom_label(aes(x=c(1:T), y=-0.5, label=round(c(rowSums(is.na(alive))/nsim), 2)), color="red")+
  scale_x_continuous(breaks=c(1:10))+scale_y_continuous(breaks=seq(0,50, by=2))+
  theme_classic(base_size=22)+
  labs(x="Years of simulated population size and\nproportion of simulations with N=0", y="Total simulated population count")
## Warning: Removed 38362 rows containing missing values or values outside the scale range
## (`geom_point()`).

# ggplot()+
#   geom_hex(data=df, aes(x=time, y=totalcount, group=simnumber), bins=10) +
#   geom_line(aes(x=c(0:T), y=bxpobj$stats[3,]), color="blue", linewidth=3)+
#   #geom_line(aes(x=c(1:T), y=c(rowSums(is.na(alive))/nsim)), col="red", linewidth=2)+
#   geom_label(aes(x=c(1:T), y=-0.5, label=round(c(rowSums(is.na(alive))/nsim), 2)), color="red")+
#   scale_x_continuous(breaks=c(1:10))+scale_y_continuous(breaks=seq(0,50, by=2))+
#   theme_classic(base_size=22)+
#   labs(x="Years of simulated population size and\nproportion of simulations with N=0", y="Total simulated population count")


# ~~~~ Plot graph with population growth rates (Fig. 3.15)  ~~~~
# op <- par(mar=c(4, 4, 2, 1), las=1, cex=1.1, "mfrow")
# layout(matrix(c(1, 1, 2, 3), 2, 2, byrow=TRUE), widths=c(1, 1), heights=c(1, 1), TRUE)
# plot(r[,1], type="l", lwd=0.5, ylab="Annual population growth rate", xlab="Time",
#     ylim=range(r[which(!is.na(alive))]), col="lightgrey", axes=FALSE)
# axis(1); axis(2)
# for (s in 2:nsim){
#   lines(r[!is.na(alive[,s]),s], lwd=0.5, col="lightgrey")
# }
# lines(apply(r, 1, mean, na.rm=TRUE), lwd=1.5)
# mtext("A", at=0, cex=1.5)
# a <- hist(mean.r, nclass=50, col="dodgerblue", main="",
#     xlab="Population growth rate", axes=FALSE) #xlim=c(-2.5, 0.1), 
# axis(1)
# axis(2, at=c(0, 5000, 10000, 15000, 20000, 25000, 30000), labels=c(0, 5, 10, 15, 20, 25, 30))
# mtext("B", at=a$mids[1], cex=1.5)
# a <- hist(mean.r[not.extinct], nclass=25, col="dodgerblue", main="",
#     xlab="Population growth rate", axes=FALSE)
# axis(1)
# axis(2, at=c(0, 2000, 4000, 6000, 8000, 10000), labels=c(0, 2, 4, 6, 8, 10))
# mtext("C", at=a$mids[1], cex=1.5)
# par(op)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# https://github.com/mikemeredith/IPM_code/blob/main/IPM_03/IPM_03.3.5.R

High Treatment simulations

# https://github.com/mikemeredith/IPM_code/blob/main/IPM_03/IPM_03.3.5.R

# 3.3 Classical analysis of a matrix population model
# ===================================================

# 3.3.5 Analysis of a matrix population model with different sources of
#       stochasticity and parameter uncertainty
# ---------------------------------------------------------------------

# Define mean, measurement error and temporal variability of the demographic parameters
mean.sj <- 0.1163615          # Mean value of juv. survival
sd.sj.e <- 0.0554588        # Uncertainty of mean juv. survival as SD on natural scale
sd.sj.t <- plogis(0.03304038)         # population variability of juv. survival as SD on logit scale # Andrew, this might have to be plogis(0.03304038), but not sure, check the text.
mean.sa <- 0.5222         # Mean value of ad. survival
sd.sa.e <- 0.05769693        # Uncertainty of mean ad. survival as SD on natural scale
sd.sa.t <- plogis(0.0386221)         # Temporal variability of ad. survival as SD on logit scale
mean.f1 <- 0.343          # Mean value of productivity of 1y females
sd.f1.e <- 0.1326032         # Uncertainty of mean productivity as SD on natural scale
sd.f1.t <- 0.1014479          # Temporal variability of productivity as SD on natural scale
mean.fa <- 0.343          # Mean value of productivity of adult females
sd.fa.e <- 0.1326032         # Uncertainty of mean productivity as SD on natural scale
sd.fa.t <- 0.101          # Temporal variability of productivity as SD on natural scale
mean.imm <- 0.192587      # Mean value of adult immigration  
sd.imm.e <- 0.06674809    # Uncertainty of mean adult immigration as SD on natural scale
sd.imm.t <- 0.02872281    # population variability of adult immigration as SD on natrual scale

# Define the number of years with predictions and the Monte Carlo setting
T <- 10                # Number of years (projection time frame)
nsim <- 10000          # Number of replicate populations simulated

# Define population matrix and initial stage-specific population sizes
N <- array(NA, dim=c(2, T+1, nsim))
N[,1,] <- c(3,1)
r <- matrix(NA, nrow=T, ncol=nsim)
alive <- matrix(NA, nrow=T, ncol=nsim)
mean.r <- numeric(nsim)

# Project population
for (s in 1:nsim){ # Loop over replicate populations
  #if(s %% 100 == 0) {cat(paste("*** Simrep", s, "***\n")) }   # Counter
  # Generate a mean of the demographic rates (subject to measurement error)
  msj <- rbeta2(1, mean.sj, sd.sj.e)
  msa <- rbeta2(1, mean.sa, sd.sa.e)
  mf1 <- rnorm(1, mean.f1, sd.f1.e)
  mfa <- rnorm(1, mean.fa, sd.fa.e)
  mia <- rnorm(1, mean.imm, sd.imm.e)

  # Generate annual demographic rates (subject to temporal variability)
  sj <- plogis(rnorm(T, qlogis(msj), sd.sj.t))
  sa <- plogis(rnorm(T, qlogis(msa), sd.sa.t))
  f1 <- pmax(0, rnorm(T, mf1, sd.f1.t))                       # Avoids negative values
  fa <- pmax(0, rnorm(T, mfa, sd.fa.t))                       # Ditto
  ia <- pmax(0, rnorm(T, mia, sd.imm.t))                       # Ditto

  # Project population (include demographic stochasticity)
  for (t in 1:T){                                             # Loop over years
    N[1,t+1,s] <- rpois(1, sj[t] * (f1[t] * N[1,t,s] + fa[t] * N[2,t,s]))
    N[2,t+1,s] <- rbinom(1, sum(N[,t,s]), sa[t])+rpois(1,ia)
    if (sum(N[,t+1,s]) == 0) break
    #r[t,s] <- log(sum(N[,t+1,s])) - log(sum(N[,t,s]))
    alive[t,s] <- t
  } #t
  #mean.r[s] <- mean(r[min(alive[,s], na.rm=TRUE):max(alive[,s], na.rm=TRUE),s])
} 

#mean(mean.r)

#sd(mean.r)


not.extinct <- which(!is.na(alive[T,]))
mean(mean.r[not.extinct])
## [1] 0
sd(mean.r[not.extinct])
## [1] 0
# Extinction probability (after T years)
sum(is.na(alive[T,])) / nsim
## [1] 0.9372
rowSums(is.na(alive)) / nsim
##  [1] 0.0554 0.2181 0.4013 0.5635 0.6808 0.7702 0.8315 0.8801 0.9137 0.9372
df <- data.frame(
  totalcount=c(colSums(N[,,1:nsim])),
  time=rep(c(0:T),nsim),
  simnumber=gl(nsim, T+1)
)


# plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3)
# boxplot(c(colSums(N[,,1:nsim]))~factor(rep(c(0:T),nsim)))
 bxpobj<-boxplot(c(colSums(N[,,1:nsim]))~factor(rep(c(0:T),nsim)), plot=F)
# plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3)
# points(bxpobj$stats[3,]~c(0:T), type="l", col="red", lwd=2)
# 
# par(mai=c(1,1,0.1,1))
# plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3)
# points(bxpobj$stats[3,]~c(0:T), type="b", col="blue", lwd=2, pch=16)
# par(new=T)
# plot(c(rowSums(is.na(alive))/nsim)~c(1:T), type="b", col="red", bty="n", xlab="", ylab="", axes=F, ylim=c(0,1), xlim=c(0,T), lwd=2, pch=16)
# axis(side=4, at=pretty(range(c(0,1))))
# mtext("probability of extinction", side=4, line=3)

par(mai=c(1,1,0.1,1))
plot(jitter(c(colSums(N[,,1:nsim])),1)~jitter(rep(c(0:T),nsim),1), pch=3, xlab="years of simulation", ylab="estimated population size")
points(bxpobj$stats[3,]~c(0:T), type="b", col="blue", lwd=2, pch=16)
par(new=T)
plot(c(rowSums(is.na(alive))/nsim)~c(1:T), type="b", col="red", bty="n", xlab="", ylab="", axes=F, ylim=c(0,1), xlim=c(0,T), lwd=2, pch=16)
axis(side=4, at=pretty(range(c(0,1))))
mtext("proportion of simulations reached N=0", side=4, line=3, col="red")

ggplot()+
 geom_line(data=df, aes(x=time, y=totalcount, group=simnumber), linewidth=1, color="gray", alpha=0.8) +
 geom_line(aes(x=c(0:T), y=bxpobj$stats[3,]), color="blue", linewidth=3)+
 #geom_line(aes(x=c(1:T), y=c(rowSums(is.na(alive))/nsim)), col="red", linewidth=2)+
 geom_label(aes(x=c(1:T), y=0, label=round(c(rowSums(is.na(alive))/nsim), 2)), color="red")+
 scale_x_continuous(breaks=c(1:10))+scale_y_continuous(breaks=seq(0,50, by=2))+
 theme_classic(base_size=22) +
 labs(x="Years of simulated population size and\nproportion of simulations with N=0", y="Total simulated population count")
## Warning: Removed 53146 rows containing missing values or values outside the scale range
## (`geom_line()`).

ggplot()+
  geom_jitter(data=df, aes(x=time, y=totalcount, group=simnumber), shape=".", width=0.3, height=0.3) +
  geom_line(aes(x=c(0:T), y=bxpobj$stats[3,]), color="blue", linewidth=3)+
  #geom_line(aes(x=c(1:T), y=c(rowSums(is.na(alive))/nsim)), col="red", linewidth=2)+
  geom_label(aes(x=c(1:T), y=-0.5, label=round(c(rowSums(is.na(alive))/nsim), 2)), color="red")+
  scale_x_continuous(breaks=c(1:10))+scale_y_continuous(breaks=seq(0,50, by=2))+
  theme_classic(base_size=22)+
  labs(x="Years of simulated population size and\nproportion of simulations with N=0", y="Total simulated population count")
## Warning: Removed 53146 rows containing missing values or values outside the scale range
## (`geom_point()`).

# ggplot()+
#   geom_hex(data=df, aes(x=time, y=totalcount, group=simnumber), bins=10) +
#   geom_line(aes(x=c(0:T), y=bxpobj$stats[3,]), color="blue", linewidth=3)+
#   #geom_line(aes(x=c(1:T), y=c(rowSums(is.na(alive))/nsim)), col="red", linewidth=2)+
#   geom_label(aes(x=c(1:T), y=-0.5, label=round(c(rowSums(is.na(alive))/nsim), 2)), color="red")+
#   scale_x_continuous(breaks=c(1:10))+scale_y_continuous(breaks=seq(0,50, by=2))+
#   theme_classic(base_size=22)+
#   labs(x="Years of simulated population size and\nproportion of simulations with N=0", y="Total simulated population count")


# ~~~~ Plot graph with population growth rates (Fig. 3.15)  ~~~~
# op <- par(mar=c(4, 4, 2, 1), las=1, cex=1.1, "mfrow")
# layout(matrix(c(1, 1, 2, 3), 2, 2, byrow=TRUE), widths=c(1, 1), heights=c(1, 1), TRUE)
# plot(r[,1], type="l", lwd=0.5, ylab="Annual population growth rate", xlab="Time",
#     ylim=range(r[which(!is.na(alive))]), col="lightgrey", axes=FALSE)
# axis(1); axis(2)
# for (s in 2:nsim){
#   lines(r[!is.na(alive[,s]),s], lwd=0.5, col="lightgrey")
# }
# lines(apply(r, 1, mean, na.rm=TRUE), lwd=1.5)
# mtext("A", at=0, cex=1.5)
# a <- hist(mean.r, nclass=50, col="dodgerblue", main="",
#     xlab="Population growth rate", axes=FALSE) #xlim=c(-2.5, 0.1), 
# axis(1)
# axis(2, at=c(0, 5000, 10000, 15000, 20000, 25000, 30000), labels=c(0, 5, 10, 15, 20, 25, 30))
# mtext("B", at=a$mids[1], cex=1.5)
# a <- hist(mean.r[not.extinct], nclass=25, col="dodgerblue", main="",
#     xlab="Population growth rate", axes=FALSE)
# axis(1)
# axis(2, at=c(0, 2000, 4000, 6000, 8000, 10000), labels=c(0, 2, 4, 6, 8, 10))
# mtext("C", at=a$mids[1], cex=1.5)
# par(op)
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# https://github.com/mikemeredith/IPM_code/blob/main/IPM_03/IPM_03.3.5.R

treatment comparisons

# # for actual treatment fecundity values
# contm2 <- out1$mean$lambda[1] #2.575
# lowm2 <- out1$mean$lambda[7] #2.264
# medm2 <- out1$mean$lambda[14] #1.605
# highm2 <- out1$mean$lambda[20] #0.343
# alpha <- out1$mean$alpha #0.9422234
# beta <- out1$mean$beta #-1.073293

probofextinctdf <- data.frame(
  treatment=c(rep("Control",10),rep("Low",10),rep("Medium", 10), rep("High",10)),
  time=rep(1:10, 4),
  probextinct=c(0.0241,0.0896, 0.1795, 0.2620, 0.3443, 0.4128, 0.4762, 0.5264, 0.5677, 0.6027,
                0.0251, 0.1022, 0.2020, 0.2966, 0.3807, 0.4602, 0.5222, 0.5747, 0.6169, 0.6544,
                0.0331, 0.1322, 0.2553, 0.3724, 0.4682, 0.5516, 0.6191, 0.6773, 0.7268, 0.7654,
                0.0543, 0.2188, 0.4035, 0.5623, 0.6821, 0.7708, 0.8324, 0.8764, 0.9078, 0.9308),
  fecundity=c(rep(2.575, 10),rep(2.264,10),rep(1.605,10),rep(0.343,10))
)

ggplot()+
  geom_point(data=probofextinctdf, aes(x=time, y=probextinct, color=factor(treatment, levels=c("Control","Low","Medium","High"))))+
  geom_line(data=probofextinctdf, aes(x=time, y=probextinct, color=factor(treatment, levels=c("Control","Low","Medium","High"))))+
  labs(color="", x="Year of simulation", y="Proportion of simulations with N=0")+
  scale_y_continuous(breaks=c(0, 0.25, 0.5, 0.75, 1.0), limits=c(0,1))+
  scale_x_continuous(breaks=c(1:10))+
  theme_classic()

plot(probextinct~fecundity, data=probofextinctdf)
abline(lm(probextinct~fecundity, data=probofextinctdf))
abline(lm(probextinct~fecundity, data=probofextinctdf|>filter(time==10)), col="red")

summary(lm(probextinct~fecundity+time, data=probofextinctdf))
## 
## Call:
## lm(formula = probextinct ~ fecundity + time, data = probofextinctdf)
## 
## Residuals:
##      Min       1Q   Median       3Q      Max 
## -0.20902 -0.02568  0.01506  0.03662  0.10939 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  0.226164   0.029695   7.616 4.35e-09 ***
## fecundity   -0.123788   0.011829 -10.465 1.31e-12 ***
## time         0.079617   0.003527  22.572  < 2e-16 ***
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.06407 on 37 degrees of freedom
## Multiple R-squared:  0.9436, Adjusted R-squared:  0.9406 
## F-statistic: 309.5 on 2 and 37 DF,  p-value: < 2.2e-16
summary(lm(probextinct~fecundity, data=probofextinctdf|>filter(time==10)))
## 
## Call:
## lm(formula = probextinct ~ fecundity, data = filter(probofextinctdf, 
##     time == 10))
## 
## Residuals:
##          1          2          3          4 
## -0.0069874 -0.0008397  0.0136363 -0.0058092 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  0.986849   0.012874   76.66  0.00017 ***
## fecundity   -0.146470   0.006773  -21.62  0.00213 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.0116 on 2 degrees of freedom
## Multiple R-squared:  0.9957, Adjusted R-squared:  0.9936 
## F-statistic: 467.6 on 1 and 2 DF,  p-value: 0.002132
summary(lm(probextinct~fecundity, data=probofextinctdf|>filter(time==5)))
## 
## Call:
## lm(formula = probextinct ~ fecundity, data = filter(probofextinctdf, 
##     time == 5))
## 
## Residuals:
##         1         2         3         4 
##  0.009575 -0.001511 -0.014634  0.006571 
## 
## Coefficients:
##              Estimate Std. Error t value Pr(>|t|)    
## (Intercept)  0.727902   0.014706   49.50 0.000408 ***
## fecundity   -0.152690   0.007737  -19.73 0.002558 ** 
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 0.01325 on 2 degrees of freedom
## Multiple R-squared:  0.9949, Adjusted R-squared:  0.9923 
## F-statistic: 389.4 on 1 and 2 DF,  p-value: 0.002558
# -0.20*(1/-0.1526)
# = 1.310616
# A reduction in fecundity of 1.31 is expected to lead to a 0.2 increase in risk of N=0 in the 5th of 10 years

# 2.5750723-1.310616=1.264456

# alpha = 0.9422234
# beta = -1.073293

# (log(1.264456)-0.9422234)/-1.073293 =
# 0.6592621
LS0tDQp0aXRsZTogInRyaW1tZWRBTUtFX3Byb2JhYmlsaXR5IG9mIG5lc3QgZmFpbHVyZSINCmF1dGhvcjogIkFuZHJldyBFYXN0Ig0KZGF0ZTogImByIFN5cy5EYXRlKClgIg0Kb3V0cHV0OiANCiAgaHRtbF9kb2N1bWVudDoNCiAgICBkZl9wcmludDogcGFnZWQNCiAgICB0b2M6IHllcw0KICAgIHRvY19mbG9hdDogeWVzDQogICAgY29kZV9mb2xkaW5nOiBoaWRlDQogICAgY29kZV9kb3dubG9hZDogeWVzDQotLS0NCg0KDQoNCmBgYHtyfQ0KDQpsaWJyYXJ5KHRpZHl2ZXJzZSkNCmxpYnJhcnkoa25pdHIpDQpsaWJyYXJ5KGphZ3NVSSkNCmxpYnJhcnkoRGlhZ3JhbW1lUikNCg0KDQpzZXQuc2VlZCgxMDE5KQ0KDQpgYGANCg0KU2VlZCBpcyBzZXQgdG8gMTAxOSBmb3IgcmVwcm9kdWNpYmlsaXR5LiAgDQoNCg0KIyBEYXRhICANCg0KTWFudWFsIGRhdGEsIHBlbi13aXNlLCBpbmNsdXNpdmUgb2YgbXVsdGlwbGUgYnJvb2RzLiAgDQoNCmBgYHtyfQ0KDQpkZmxvbmdmb3Jjb3VudCA8LSBkYXRhLmZyYW1lKA0KICBkb3NlPWZhY3RvcihjKHJlcCgiY29udCIsNikscmVwKCJsb3ciLDcpLHJlcCgibWVkIiw2KSxyZXAoImhpZ2giLDgpKSwNCiAgICAgICAgICAgICAgbGV2ZWxzPWMoImNvbnQiLCJsb3ciLCJtZWQiLCJoaWdoIikpLA0KICBkb3NlbnVtPWMocmVwKDAuMDAwMTIxLDYpLHJlcCgwLjEyMSw3KSxyZXAoMC40NSw2KSxyZXAoMi4wNCw4KSksDQogIHBlbj1jKDMxLDMyLDMzLDM0LDM1LDM1LDM2LDM3LDM4LDM4LDM5LDQwLDQwLDQxLDQyLDQzLDQzLDQ0LDQ1LDQ2LDQ2LDQ2LDQ3LDQ4LDQ4LDQ4LDUwKSwNCiAgY2x1dGNoPWMoMSwxLDEsMSwxLDIsMSwxLDEsMiwxLDEsMiwxLDEsMSwyLDEsMSwxLDIsMywxLDEsMiwzLDEpLA0KICBudW1oYXRjaGVkPWMoMywyLDIsMSwwLDAsNCwxLDAsMywzLDAsMCwzLDAsMCwwLDEsMSwwLDAsMCwyLDAsMCwwLDIpDQopDQoNCmRmbG9uZ2ZvcmNvdW50JGZhaWx1cmUgPC0gaWZlbHNlKGRmbG9uZ2ZvcmNvdW50JG51bWhhdGNoZWQ9PTAsMSwwKQ0KDQoNCmBgYA0KDQoNCiMgSkFHUyBzZXR1cCBhbmQgcnVuIG9mIFBvaXNzb24gR0xNICANCg0KYGBge3J9DQoNCmphZ3MuZGF0YSA8LSBsaXN0KHk9ZGZsb25nZm9yY291bnQkbnVtaGF0Y2hlZCwNCiAgICAgICAgICAgICAgICAgIGNvbmM9ZGZsb25nZm9yY291bnQkZG9zZW51bSwNCiAgICAgICAgICAgICAgICAgIG49bnJvdyhkZmxvbmdmb3Jjb3VudCkpDQoNCmNhdChmaWxlPSJtb2RlbF9BTUtFX3BvaXNzb25fZWdncyBoYXRjaGVkIGJ5IG5vcm1hbCBkb3NlLnR4dCIsIg0KICBtb2RlbHsNCiAgI3ByaW9ycyBhbmQgbGluZWFyIG1vZGVscw0KICBhbHBoYSB+IGRub3JtKGxvZygzKSwxMDApICMgbWVhbiBhbmQgcHJlY2lzaW9uIGluIGphZ3MgcHJlY2lzaW9uIGlzIGludmVyc2Ugb2YgdGhlIHZhcmlhbmNlLCBzbyAxL3NpZ21hXjIgYW5kIGluIHRoaXMgY2FzZSBzdWdnZXN0cyB0aGUgcHJpb3JzIGFyZSBtZWFuPTAsIHNkPTAuMSAoZXhwKDAuMSkgb24gdGhlIHJlYWwgc2NhbGUpIChzcXJ0KDEvMTAwKSkNCiAgYmV0YSB+IGRub3JtKDAsMC4wMDEpDQogICAgDQogICNsaWtlbGlob29kIGZvciB0aGUgcG9pc3NvbiBHTE0NCiAgZm9yKGkgaW4gMTpuKXsNCiAgICB5W2ldIH4gZHBvaXMobGFtYmRhW2ldKSAjc3RvY2hhc3RpYw0KICAgIGxvZyhsYW1iZGFbaV0pIDwtIGFscGhhICsgYmV0YSAqIGNvbmNbaV0NCiAgfQ0KICBtZWFuLmV4cC5jb3VudCA8LSBleHAoYWxwaGEpDQp9DQoiKQ0KDQppbml0cyA8LSBmdW5jdGlvbigpe2xpc3QoYWxwaGE9cm5vcm0oMSwwLDEpLGJldGE9cm5vcm0oMSwwLDEpKX0NCg0KcGFyYW1ldGVycyA8LSBjKCJhbHBoYSIsImJldGEiLCJtZWFuLmV4cC5jb3VudCIsImxhbWJkYSIpDQoNCm5pIDwtIDUwMDAwDQpuYiA8LSAxMDAwMA0KbmMgPC0gMw0KbnQgPC0gMTANCm5hIDwtIDEwMDANCg0Kb3V0MSA8LSBqYWdzKGphZ3MuZGF0YSwgaW5pdHMsIHBhcmFtZXRlcnMsICJtb2RlbF9BTUtFX3BvaXNzb25fZWdncyBoYXRjaGVkIGJ5IG5vcm1hbCBkb3NlLnR4dCIsIG4uaXRlcj1uaSwgbi5idXJuaW49bmIsIG4uY2hhaW5zPW5jLCBuLnRoaW49bnQsIG4uYWRhcHQ9bmEsIHBhcmFsbGVsPVQpDQoNCnRlc3QgPC0gZGF0YS5mcmFtZShvdXQxJHNpbXMubGlzdFsxOjJdKQ0KI3dyaXRlX2Nzdih0ZXN0LCAib3V0MXBvc3RlcmlvcmFscGhhYW5kYmV0YS5jc3YiKQ0KDQoNCmBgYA0KDQoNCiQkDQpcYWxwaGEgXHNpbSBOKDMsMC4xKVxcDQpcYmV0YSBcc2ltIE4oMCwzMS42MilcXA0KeSBcc2ltIFBvaXNzb24oXGxhbWJkYSlcXA0KbG9nKFxsYW1iZGEpID0gYWxwaGEgKyBcYmV0YSBcc3VtIFBGQVMNCiQkDQoNCg0KIyMgSkFHUyBvdXRwdXQgd3JhbmdsaW5nIGZvciBQb2lzc29uIEdMTSAgDQoNCg0KYGBge3J9DQoNCmNvbnRtIDwtIG91dDEkbWVhbiRsYW1iZGFbMV0gIzIuNTc1DQpsb3dtIDwtIG91dDEkbWVhbiRsYW1iZGFbN10gIzIuMjY0DQptZWRtIDwtIG91dDEkbWVhbiRsYW1iZGFbMTRdICMxLjYwNQ0KaGlnaG0gPC0gb3V0MSRtZWFuJGxhbWJkYVsyMF0gIzAuMzQzDQoNCmNvbnRsIDwtIG91dDEkcTIuNSRsYW1iZGFbMV0gIzIuMTY0DQpsb3dsIDwtIG91dDEkcTIuNSRsYW1iZGFbN10gIzEuOTA2DQptZWRsIDwtIG91dDEkcTIuNSRsYW1iZGFbMTRdICMxLjE4MQ0KaGlnaGwgPC0gb3V0MSRxMi41JGxhbWJkYVsyMF0gIzAuMDgxDQoNCmNvbnR1IDwtIG91dDEkcTk3LjUkbGFtYmRhWzFdICMzLjA0MQ0KbG93dSA8LSBvdXQxJHE5Ny41JGxhbWJkYVs3XSAjMi42Ng0KbWVkdSA8LSBvdXQxJHE5Ny41JGxhbWJkYVsxNF0gIzIuMDM0DQpoaWdodSA8LSBvdXQxJHE5Ny41JGxhbWJkYVsyMF0gIzAuODEyDQoNCg0KIyMjIHByb2JhYmlsaXR5IG9mIGhhdmluZyBhIGNlcnRhaW4gbnVtYmVyIG9mIHZpYWJsZSBlZ2dzDQoNCmNvdW50ZWdnZGYgPC0gZGF0YS5mcmFtZSgNCiAgZG9zZT1jKDAuMDAwMTIxLCAwLjEyMSwgMC40NSwgMi4wNCksDQogIG1lYW49Yyhjb250bSwgbG93bSwgbWVkbSwgaGlnaG0pLA0KICBsb3dlcj1jKGNvbnRsLCBsb3dsLCBtZWRsLCBoaWdobCksDQogIHVwcGVyPWMoY29udHUsIGxvd3UsIG1lZHUsIGhpZ2h1KQ0KKQ0KDQplZmZlY3R6ZXJvZGYgPC0gZGF0YS5mcmFtZSgNCiAgZG9zZT1jKDAuMDAwMTIxLCAwLjEyMSwgMC40NSwgMi4wNCksDQogIG1lYW49YyhkcG9pcygwLCBsYW1iZGE9Y29udG0pLGRwb2lzKDAsIGxhbWJkYT1sb3dtKSxkcG9pcygwLCBsYW1iZGE9bWVkbSksZHBvaXMoMCwgbGFtYmRhPWhpZ2htKSksDQogIGxvd2VyPWMoZHBvaXMoMCwgbGFtYmRhPWNvbnRsKSxkcG9pcygwLCBsYW1iZGE9bG93bCksZHBvaXMoMCwgbGFtYmRhPW1lZGwpLGRwb2lzKDAsIGxhbWJkYT1oaWdobCkpLA0KICB1cHBlcj1jKGRwb2lzKDAsIGxhbWJkYT1jb250dSksZHBvaXMoMCwgbGFtYmRhPWxvd3UpLGRwb2lzKDAsIGxhbWJkYT1tZWR1KSxkcG9pcygwLCBsYW1iZGE9aGlnaHUpKSwNCiAgaGF0Y2hlZGVnZ3M9cmVwKDAsNCkNCikNCg0KZWZmZWN0M2RmIDwtIGRhdGEuZnJhbWUoDQogIGRvc2U9YygwLjAwMDEyMSwgMC4xMjEsIDAuNDUsIDIuMDQpLA0KICBtZWFuPWMoZHBvaXMoMywgbGFtYmRhPWNvbnRtKSxkcG9pcygzLCBsYW1iZGE9bG93bSksZHBvaXMoMywgbGFtYmRhPW1lZG0pLGRwb2lzKDMsIGxhbWJkYT1oaWdobSkpLA0KICBsb3dlcj1jKGRwb2lzKDMsIGxhbWJkYT1jb250bCksZHBvaXMoMywgbGFtYmRhPWxvd2wpLGRwb2lzKDMsIGxhbWJkYT1tZWRsKSxkcG9pcygzLCBsYW1iZGE9aGlnaGwpKSwNCiAgdXBwZXI9YyhkcG9pcygzLCBsYW1iZGE9Y29udHUpLGRwb2lzKDMsIGxhbWJkYT1sb3d1KSxkcG9pcygzLCBsYW1iZGE9bWVkdSksZHBvaXMoMywgbGFtYmRhPWhpZ2h1KSksDQogIGhhdGNoZWRlZ2dzPXJlcCgzLDQpDQopDQoNCmVmZmVjdDJkZiA8LSBkYXRhLmZyYW1lKA0KICBkb3NlPWMoMC4wMDAxMjEsIDAuMTIxLCAwLjQ1LCAyLjA0KSwNCiAgbWVhbj1jKGRwb2lzKDIsIGxhbWJkYT1jb250bSksZHBvaXMoMiwgbGFtYmRhPWxvd20pLGRwb2lzKDIsIGxhbWJkYT1tZWRtKSxkcG9pcygyLCBsYW1iZGE9aGlnaG0pKSwNCiAgbG93ZXI9YyhkcG9pcygyLCBsYW1iZGE9Y29udGwpLGRwb2lzKDIsIGxhbWJkYT1sb3dsKSxkcG9pcygyLCBsYW1iZGE9bWVkbCksZHBvaXMoMiwgbGFtYmRhPWhpZ2hsKSksDQogIHVwcGVyPWMoZHBvaXMoMiwgbGFtYmRhPWNvbnR1KSxkcG9pcygyLCBsYW1iZGE9bG93dSksZHBvaXMoMiwgbGFtYmRhPW1lZHUpLGRwb2lzKDIsIGxhbWJkYT1oaWdodSkpLA0KICBoYXRjaGVkZWdncz1yZXAoMiw0KQ0KKQ0KDQplZmZlY3Q1ZGYgPC0gZGF0YS5mcmFtZSgNCiAgZG9zZT1jKDAuMDAwMTIxLCAwLjEyMSwgMC40NSwgMi4wNCksDQogIG1lYW49YyhkcG9pcyg1LCBsYW1iZGE9Y29udG0pLGRwb2lzKDUsIGxhbWJkYT1sb3dtKSxkcG9pcyg1LCBsYW1iZGE9bWVkbSksZHBvaXMoNSwgbGFtYmRhPWhpZ2htKSksDQogIGxvd2VyPWMoZHBvaXMoNSwgbGFtYmRhPWNvbnRsKSxkcG9pcyg1LCBsYW1iZGE9bG93bCksZHBvaXMoNSwgbGFtYmRhPW1lZGwpLGRwb2lzKDUsIGxhbWJkYT1oaWdobCkpLA0KICB1cHBlcj1jKGRwb2lzKDUsIGxhbWJkYT1jb250dSksZHBvaXMoNSwgbGFtYmRhPWxvd3UpLGRwb2lzKDUsIGxhbWJkYT1tZWR1KSxkcG9pcyg1LCBsYW1iZGE9aGlnaHUpKSwNCiAgaGF0Y2hlZGVnZ3M9cmVwKDUsNCkNCikNCg0KZWZmZWN0MWRmIDwtIGRhdGEuZnJhbWUoDQogIGRvc2U9YygwLjAwMDEyMSwgMC4xMjEsIDAuNDUsIDIuMDQpLA0KICBtZWFuPWMoZHBvaXMoMSwgbGFtYmRhPWNvbnRtKSxkcG9pcygxLCBsYW1iZGE9bG93bSksZHBvaXMoMSwgbGFtYmRhPW1lZG0pLGRwb2lzKDEsIGxhbWJkYT1oaWdobSkpLA0KICBsb3dlcj1jKGRwb2lzKDEsIGxhbWJkYT1jb250bCksZHBvaXMoMSwgbGFtYmRhPWxvd2wpLGRwb2lzKDEsIGxhbWJkYT1tZWRsKSxkcG9pcygxLCBsYW1iZGE9aGlnaGwpKSwNCiAgdXBwZXI9YyhkcG9pcygxLCBsYW1iZGE9Y29udHUpLGRwb2lzKDEsIGxhbWJkYT1sb3d1KSxkcG9pcygxLCBsYW1iZGE9bWVkdSksZHBvaXMoMSwgbGFtYmRhPWhpZ2h1KSksDQogIGhhdGNoZWRlZ2dzPXJlcCgxLDQpDQopDQoNCmVmZmVjdDRkZiA8LSBkYXRhLmZyYW1lKA0KICBkb3NlPWMoMC4wMDAxMjEsIDAuMTIxLCAwLjQ1LCAyLjA0KSwNCiAgbWVhbj1jKGRwb2lzKDQsIGxhbWJkYT1jb250bSksZHBvaXMoNCwgbGFtYmRhPWxvd20pLGRwb2lzKDQsIGxhbWJkYT1tZWRtKSxkcG9pcyg0LCBsYW1iZGE9aGlnaG0pKSwNCiAgbG93ZXI9YyhkcG9pcyg0LCBsYW1iZGE9Y29udGwpLGRwb2lzKDQsIGxhbWJkYT1sb3dsKSxkcG9pcyg0LCBsYW1iZGE9bWVkbCksZHBvaXMoNCwgbGFtYmRhPWhpZ2hsKSksDQogIHVwcGVyPWMoZHBvaXMoNCwgbGFtYmRhPWNvbnR1KSxkcG9pcyg0LCBsYW1iZGE9bG93dSksZHBvaXMoNCwgbGFtYmRhPW1lZHUpLGRwb2lzKDQsIGxhbWJkYT1oaWdodSkpLA0KICBoYXRjaGVkZWdncz1yZXAoNCw0KQ0KKQ0KDQpiaWdlZ2dwcm9iZGYgPC0gcmJpbmQoDQogIGVmZmVjdHplcm9kZiwNCiAgZWZmZWN0MWRmLA0KICBlZmZlY3QyZGYsDQogIGVmZmVjdDNkZiwNCiAgZWZmZWN0NGRmLA0KICBlZmZlY3Q1ZGYNCikNCg0KDQpgYGANCg0KIyBUYWJsZSBvZiBQb2lzc29uIEdMTSBvdXRwdXQgIA0KDQpQcm9iYWJpbGl0eSBvZiBoYXZpbmcgYSBjZXJ0YWluIG51bWJlciBvZiBoYXRjaGVkIGVnZ3MgYXQgZWFjaCBkb3NlIHdpdGggY29uZmlkZW5jZSBpbnRlcnZhbHMuICANCk5vdGUgdGhhdCB1cHBlciBhbmQgbG93ZXIgYXJlIHN0cmFuZ2UgYmVjYXVzZSBzb21lIGRvc2UgcmVzcG9uc2UgYXJlIGRlY3JlYXNpbmcgYW5kIHNvbWUgYXJlIGluY3JlYXNpbmcgZGVwZW5kaW5nIG9uIHRoZSBudW1iZXIgb2YgaGF0Y2hlZCBlZ2dzLiAgDQoNCmBgYHtyfQ0KDQpiaWdlZ2dwcm9iZGYgfD4NCiAgI2ZpbHRlcihoYXRjaGVkZWdncz09MCl8Pg0KICBrYWJsZSgsIGRpZ2l0cz01KQ0KDQpgYGANCg0KDQojIEludGVycG9sYXRlIGFkdmVyc2UgaW5jcmVhc2UgaW4gcHJvYmFiaWxpdHkgb2YgbmVzdCBmYWlsdXJlIHVzaW5nIFBvaXNzb24gR0xNICANCg0KVXNpbmcgdGhlIHBvc3RlcmlvciBkcmF3cywgZmluZCB0aGUgZG9zZXMgYnJhY2tldGluZyA5NSUgcHJvYmFiaWxpdHkgb2Ygb2JzZXJ2aW5nIHRoYXQgYW1vdW50IG9mIG5lc3QgZmFpbHVyZS4gIA0KDQojIyBCYWNrZ3JvdW5kIHByb2JhYmlsaXR5IG9mIGhhdmluZyB6ZXJvIGhhdGNoZWQgZWdncyAgDQoNCmBgYHtyfQ0KZHBvaXMoMCxsYW1iZGE9Y29udG0pDQoNCmBgYA0KDQojIyAwLjIgYWRkZWQgcmlzayBvZiBoYXZpbmcgemVybyBoYXRjaGVkIGVnZ3MgIA0KDQpgYGB7cn0NCmRwb2lzKDAsbGFtYmRhPWNvbnRtKSswLjINCg0KYGBgDQoNCiMjIEhpZ2hlc3QgY29uY2VudHJhdGlvbiB3aGVyZSBwcm9iYWJpbGl0eSBvZiBoYXZpbmcgemVybyBlZ2dzIGlzIDwwLjI4ICANCg0KaS5lLiAic2FmZSIgY29uY2VudHJhdGlvbg0KDQpgYGB7cn0NCg0KIyMjIGRvIHByZWRpY3Rpb24gaW50ZXJwb2xhdGlvbiBmb3IgaGF2aW5nIHplcm8NCg0KYWx0LmNvbmMucHJlZCA8LSBzZXEoZnJvbT0wLjAwMDEsdG89MywgbGVuZ3RoLm91dD0xMDAwKQ0KcHJlZDIgPC0gYXJyYXkoTkEsZGltPWMobGVuZ3RoKGFsdC5jb25jLnByZWQpLDEyMDAwKSkNCmZvcihpIGluIDE6MTIwMDApew0KICBwcmVkMlssaV0gPC0gZXhwKG91dDEkc2ltcy5saXN0JGFscGhhW2ldK291dDEkc2ltcy5saXN0JGJldGFbaV0qYWx0LmNvbmMucHJlZCkNCn0NCg0KcG0yIDwtIGFwcGx5KHByZWQyLDEsIG1lYW4pDQpwbTJsIDwtIGFwcGx5KHByZWQyLDEsIHF1YW50aWxlLCBwcm9icz0wLjk3NSkNCnBtMnUgPC0gYXBwbHkocHJlZDIsMSwgcXVhbnRpbGUsIHByb2JzPTAuMDI1KQ0KDQpwcm9iIDwtIGFwcGx5KHByZWQyLCAxLCBmdW5jdGlvbih4KSBtZWFuKCh4LTEpPDApKQ0KDQpkcHJvYjAgPC0gYXBwbHkocHJlZDIsMSxmdW5jdGlvbih4KSBtZWFuKGRwb2lzKDAsbGFtYmRhPXgpKSkNCmRwcm9iMG1pbiA8LSBhcHBseShwcmVkMiwxLGZ1bmN0aW9uKHgpIHF1YW50aWxlKGRwb2lzKDAsbGFtYmRhPXgpLCBwcm9icz0wLjA1KSkNCmRwcm9iMG1heCA8LSBhcHBseShwcmVkMiwxLGZ1bmN0aW9uKHgpIHF1YW50aWxlKGRwb2lzKDAsbGFtYmRhPXgpLCBwcm9icz0wLjk1KSkNCg0KI3Bsb3QoZHByb2IwfmFsdC5jb25jLnByZWQsIHlsaW09YygwLDEpKQ0KI3BvaW50cyhkcHJvYjBtaW5+YWx0LmNvbmMucHJlZCwgY29sPSJkYXJrZ3JheSIpDQojcG9pbnRzKGRwcm9iMG1heH5hbHQuY29uYy5wcmVkLCBjb2w9ImRhcmtncmF5IikNCg0KDQptaW50d2VudHl0aHJlc2hvbGQgPC0gbWF4KGFsdC5jb25jLnByZWRbZHByb2IwbWluPDAuMjhdKQ0KbWF4dHdlbnR5dGhyZXNob2xkIDwtIG1heChhbHQuY29uYy5wcmVkW2Rwcm9iMG1heDwwLjI4XSkNCm1lYW50d2VudHl0aHJlc2hvbGQgPC0gbWF4KGFsdC5jb25jLnByZWRbZHByb2IwPDAuMjhdKQ0KbWludHdlbnR5dGhyZXNob2xkDQptZWFudHdlbnR5dGhyZXNob2xkDQptYXh0d2VudHl0aHJlc2hvbGQNCg0KYGBgDQoNCiMjIFBsb3Qgb2YgcHJlZGljdGVkIG51bWJlciBvZiBlZ2dzICANCg0KYGBge3IsIG51bWJlcm9maGF0Y2hlZGRvc2VyZXNwb25zZSwgZmlnLnBhdGg9J2ZpZ3VyZXMvJyxkZXY9YygncG5nJywgJ3RpZmYnLCAnanBlZycpLCBkcGk9MzAwLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD02fQ0KDQpwYXIobWFpPWMoMiwxLjIsMC4xLDAuMykpDQpwbG90KGppdHRlcihudW1oYXRjaGVkLCAwLjUpfmppdHRlcihhcy5udW1lcmljKGZhY3Rvcihkb3NlKSkpLCBkYXRhPWRmbG9uZ2ZvcmNvdW50LCBwY2g9MywgeWxhYj0iTnVtYmVyIG9mIGhhdGNoZWQgZWdncyIsIHhsYWI9ZXhwcmVzc2lvbihBZHVsdH5kYWlseX5kb3Nlfm1nL2tnflNpZ21hKlBGQVMpLA0KICAgICBidHk9Im4iLCBsYXM9MSwgYXhlcz1GLCBjZXgubGFiPTEuNSkNCmF4aXMoMSwgYXQ9YygxLDIsMyw0KSwgbGFiZWxzPWMoIjAuMDAwMTIxIiwgIjAuMTIxIiwgIjAuNDUiLCAiMi4wNCIpLCBmb250PTEsIGNleC5heGlzPTEuNSkNCmF4aXMoMiwgYXQ9YygwLDEsMiwzLDQpLCBsYWJlbHM9YygwLDEsMiwzLDQpLCBmb250PTEsIGxhcz0xLCBjZXguYXhpcz0xLjUpDQphcnJvd3MoYXMubnVtZXJpYyhmYWN0b3IoY291bnRlZ2dkZiRkb3NlKSksY291bnRlZ2dkZiRsb3dlcixhcy5udW1lcmljKGZhY3Rvcihjb3VudGVnZ2RmJGRvc2UpKSxjb3VudGVnZ2RmJHVwcGVyLCBsd2Q9MiwgbGVuZ3RoPTAuMSwgYW5nbGU9OTAsIGNvZGU9MywgY29sPWMoImRhcmtncmVlbiIsImJsdWUiLCJkYXJrb3JhbmdlIiwicmVkIikpDQpwb2ludHMobWVhbn5hcy5udW1lcmljKGZhY3Rvcihkb3NlKSksIGRhdGE9Y291bnRlZ2dkZiwgdHlwZT0ibCIsIGNvbD0iZGFya2dyYXkiLCBsd2Q9MikNCnBvaW50cyhtZWFufmFzLm51bWVyaWMoZmFjdG9yKGRvc2UpKSwgZGF0YT1jb3VudGVnZ2RmLCB0eXBlPSJwIiwgY29sPWMoImRhcmtncmVlbiIsImJsdWUiLCJkYXJrb3JhbmdlIiwicmVkIiksIHBjaD0xNiwgY2V4PTEuNSkNCnBvaW50cyhjKDEuMSwxLjEpLGMoMi45NSwzLjA1KSxjb2w9InB1cnBsZSIsIHBjaD0yKQ0KYXhpcygxLCBhdD1jKDEsMiwzLDQpLCBsYWJlbHM9YygiMC4wMDMiLCAiMy4zNSIsICI4LjM0IiwgIjY1Ljg0IiksIGZvbnQ9MSwgY2V4LmF4aXM9MS41LCBsaW5lPTUpDQptdGV4dChleHByZXNzaW9uKE1lYW5+ZWdnfm1nL2tnflNpZ21hKlBGQVMpLCBzaWRlPTEsIGxpbmU9OCwgZm9udD0xLCBjZXg9MS41KQ0KDQoNCmBgYA0KDQoNCmBgYHtyLCBoYXRjaGVkZWdnc3dpdGhwb3B0aHJlc2hvbGRzLCBmaWcucGF0aD0nZmlndXJlcy8nLGRldj1jKCdwbmcnLCAndGlmZicsICdqcGVnJyksIGRwaT0zMDAsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTZ9DQoNCnBhcihtYWk9YygxLDEsMC4xLDAuMSkpDQpwbG90KHBtMn5hbHQuY29uYy5wcmVkLCBsb2c9IiIsIHlsaW09YygwLDMpLCB0eXBlPSJsIiwgYnR5PSJuIiwgeGxpbT1jKC0wLjI1LDMpLA0KICAgICB5bGFiPSJNZWFuIG51bWJlciBvZiBoYXRjaGVkIGVnZ3MiLCB4bGFiPWV4cHJlc3Npb24ocGFzdGUoIkFkdWx0IGRhaWx5IGRvc2UgIiwgU2lnbWEsIlBGQVMgbWcva2ciKSksIGxhcz0xLA0KICAgICBmb250PTEsIGZvbnQubGFiPTEsIHBjaD0xNiwgY2V4PTIsIGx3ZD0yLCBjZXgubGFiPTEuNSwgY2V4LmF4aXM9MS41KQ0KcG9pbnRzKHBtMmx+YWx0LmNvbmMucHJlZCwgdHlwZT0ibCIsIGx0eT0yLCBjb2w9ImRhcmtncmF5IiwgbHdkPTIpDQpwb2ludHMocG0ydX5hbHQuY29uYy5wcmVkLCB0eXBlPSJsIiwgbHR5PTIsIGNvbD0iZGFya2dyYXkiLCBsd2Q9MikNCnRleHQoLTAuMzUsMi41NzUsIjIuNTc1IiwgcG9zPTQsIGNvbD0iZGFya2dyZWVuIikNCnRleHQoLTAuMzUsMS4yNjQ0NTYsIjEuMjY0IiwgcG9zPTQsIGNvbD0icmVkIikNCnNlZ21lbnRzKDAsMS4yNjQ0NTYsMS41LDEuMjY0NDU2LCBjb2w9InJlZCIpDQpzZWdtZW50cygwLjY3NTc1MzIsMS4yNjQ0NTYsMC42NzU3NTMyLDAuNSwgY29sPSJibGFjayIpDQp0ZXh0KDAuNjc1NzUzMiwwLjUsIjAuNjggbWcva2ciLCBwb3M9MSwgY29sPSJibGFjayIsIHhwZD1OQSkNCnNlZ21lbnRzKDAuNDA1NDkxOSwxLjI2NDQ1NiwwLjQwNTQ5MTksMS4wNjQ0NTYsIGNvbD0iYmxhY2siKQ0KI3RleHQoMC40MzI1MTgsMC40OCwiMC40MyBtZy9rZ1xuUCgwIGVnZ3MpPDAuMjgiLCBwb3M9MywgY29sPSJibGFjayIpDQp0ZXh0KDAuNDA1NDkxOSwxLjA2NDQ1NiwiMC40MSBtZy9rZyIsIHBvcz0xLCBjb2w9ImJsYWNrIikNCnNlZ21lbnRzKDEuMjM3Mjk2LDEuMjY0NDU2LDEuMjM3Mjk2LDEuNDY0NDU2LCBjb2w9ImJsYWNrIikNCiN0ZXh0KDEuMDkwMTU0LDAuMTgsIjEuMDkgbWcva2dcblAoMCBlZ2dzKTwwLjI4IiwgcG9zPTEsIGNvbD0iYmxhY2siLCB4cGQ9TkEpDQp0ZXh0KDEuMjM3Mjk2LDEuNDY0NDU2LCIxLjI0IG1nL2tnIiwgcG9zPTMsIGNvbD0iYmxhY2siLCB4cGQ9TkEpDQoNCg0KbWF4KGFsdC5jb25jLnByZWRbcG0yPjEuMjY0NDU2XSkNCm1heChhbHQuY29uYy5wcmVkW3BtMmw+MS4yNjQ0NTZdKQ0KbWF4KGFsdC5jb25jLnByZWRbcG0ydT4xLjI2NDQ1Nl0pDQpgYGANCg0KDQoNCmBgYHtyLCBpbnRlcnBvbGF0ZWRwcm9iYWJpbGl0eW9maGF2aW5nemVyb2hhdGNoZWRlZ2dzLCBmaWcucGF0aD0nZmlndXJlcy8nLGRldj1jKCdwbmcnLCAndGlmZicsICdqcGVnJyksIGRwaT0zMDAsIGZpZy5oZWlnaHQ9NS42LCBmaWcud2lkdGg9N30NCg0KcGFyKG1haT1jKDEuMiwxLjIsMC4xLDAuNzUpKQ0KcGxvdChkcHJvYjB+YWx0LmNvbmMucHJlZCwgbG9nPSIiLCB5bGltPWMoMCwxKSwgdHlwZT0ibCIsIGJ0eT0ibiIsIHhsaW09YygtMC4yNSwzKSwNCiAgICAgeWxhYj0iUHJvYmFiaWxpdHkgb2YgaGF2aW5nIDAgaGF0Y2hlZCBlZ2dzIiwgeGxhYj1leHByZXNzaW9uKHBhc3RlKCJBZHVsdCBkYWlseSBkb3NlICIsIFNpZ21hLCJQRkFTIG1nL2tnIikpLCBsYXM9MSwNCiAgICAgZm9udD0xLCBmb250LmxhYj0xLCBwY2g9MTYsIGNleD0yLCBsd2Q9MiwgY2V4LmxhYj0xLjUsIGNleC5heGlzPTEuNSkNCnBvaW50cyhkcHJvYjBtaW5+YWx0LmNvbmMucHJlZCwgdHlwZT0ibCIsIGx0eT0yLCBjb2w9ImRhcmtncmF5IiwgbHdkPTIpDQpwb2ludHMoZHByb2IwbWF4fmFsdC5jb25jLnByZWQsIHR5cGU9ImwiLCBsdHk9MiwgY29sPSJkYXJrZ3JheSIsIGx3ZD0yKQ0KYWJsaW5lKGg9YygwLDEpKQ0KdGV4dCgtMC4zNSxkcG9pcygwLGxhbWJkYT1jb250bSksIjAuMDgiLCBwb3M9NCwgY29sPSJkYXJrZ3JlZW4iKQ0KdGV4dCgtMC4zNSxkcG9pcygwLGxhbWJkYT1jb250bSkrMC4yLCIwLjI4IiwgcG9zPTQsIGNvbD0icmVkIikNCnNlZ21lbnRzKDAsZHBvaXMoMCxsYW1iZGE9Y29udG0pKzAuMiwxLjUsZHBvaXMoMCxsYW1iZGE9Y29udG0pKzAuMiwgY29sPSJyZWQiKQ0Kc2VnbWVudHMoMC40MzI1MTgsMC4yOCwwLjQzMjUxOCwwLjQ4LCBjb2w9ImJsYWNrIikNCiN0ZXh0KDAuNDMyNTE4LDAuNDgsIjAuNDMgbWcva2dcblAoMCBlZ2dzKTwwLjI4IiwgcG9zPTMsIGNvbD0iYmxhY2siKQ0KdGV4dCgwLjQzMjUxOCwwLjQ4LCIwLjQzIG1nL2tnIiwgcG9zPTMsIGNvbD0iYmxhY2siKQ0Kc2VnbWVudHMoMS4wOTAxNTQsMC4yOCwxLjA5MDE1NCwwLjE4LCBjb2w9ImJsYWNrIikNCiN0ZXh0KDEuMDkwMTU0LDAuMTgsIjEuMDkgbWcva2dcblAoMCBlZ2dzKTwwLjI4IiwgcG9zPTEsIGNvbD0iYmxhY2siLCB4cGQ9TkEpDQp0ZXh0KDEuMDkwMTU0LDAuMTgsIjEuMDkgbWcva2ciLCBwb3M9MSwgY29sPSJibGFjayIsIHhwZD1OQSkNCnNlZ21lbnRzKDAuNjQ4NzI3LDAuMjgsMC42NDg3MjcsMC4wOCwgY29sPSJibGFjayIpDQp0ZXh0KDAuNjQ4NzI3LDAuMDgsIjAuNjUgbWcva2ciLCBwb3M9MSwgY29sPSJibGFjayIsIHhwZD1OQSkNCg0KYGBgDQoNCg0KDQoNCg0KIyBKQUdTIHNldHVwIGFuZCBydW4gb2YgQmVybm91bGxpIEdMTSAgDQoNCmBgYHtyfQ0KDQpqYWdzLmRhdGEyIDwtIGxpc3QoeT1kZmxvbmdmb3Jjb3VudCRmYWlsdXJlLA0KICAgICAgICAgICAgICAgICAgY29uYz1kZmxvbmdmb3Jjb3VudCRkb3NlbnVtLA0KICAgICAgICAgICAgICAgICAgbj1ucm93KGRmbG9uZ2ZvcmNvdW50KSkNCg0KY2F0KGZpbGU9Im1vZGVsX0FNS0VfYmVybm91bGxpX2VnZ3MgaGF0Y2hlZCBieSBub3JtYWwgZG9zZS50eHQiLCINCiAgbW9kZWx7DQogICNwcmlvcnMgYW5kIGxpbmVhciBtb2RlbHMNCiAgYWxwaGEgPC0gbG9naXQobWVhbi50aGV0YSkNCiAgbWVhbi50aGV0YSB+IGR1bmlmKDAsMC41KQ0KICBiZXRhIH4gZG5vcm0oMCwwLjAwMSkNCiAgICANCiAgI2xpa2VsaWhvb2QgZm9yIHRoZSBiZXJub3VsbGkgR0xNDQogIGZvcihpIGluIDE6IG4pew0KICAgIHlbaV0gfiBkYmVybih0aGV0YVtpXSkgI3N0b2NoYXN0aWMNCiAgICBsb2dpdCh0aGV0YVtpXSkgPC0gYWxwaGEgKyBiZXRhICogY29uY1tpXQ0KICB9DQp9DQoiKQ0KDQppbml0czIgPC0gZnVuY3Rpb24oKXtsaXN0KG1lYW4udGhldGE9cnVuaWYoMSwwLCAwLjUpLGJldGE9cm5vcm0oMSwwLDEpKX0NCg0KcGFyYW1ldGVyczIgPC0gYygiYWxwaGEiLCJiZXRhIiwibWVhbi50aGV0YSIsInRoZXRhIikNCg0KbmkgPC0gNTAwMDANCm5iIDwtIDEwMDAwDQpuYyA8LSAzDQpudCA8LSAxMA0KbmEgPC0gMTAwMA0KDQpvdXQyIDwtIGphZ3MoamFncy5kYXRhMiwgaW5pdHMyLCBwYXJhbWV0ZXJzMiwgIm1vZGVsX0FNS0VfYmVybm91bGxpX2VnZ3MgaGF0Y2hlZCBieSBub3JtYWwgZG9zZS50eHQiLCBuLml0ZXI9bmksIG4uYnVybmluPW5iLCBuLmNoYWlucz1uYywgbi50aGluPW50LCBuLmFkYXB0PW5hLCBwYXJhbGxlbD1UKQ0KDQojamFnc1VJOjp0cmFjZXBsb3Qob3V0MikNCg0KdGVzdDIgPC0gZGF0YS5mcmFtZShvdXQyJHNpbXMubGlzdFsxOjJdKQ0KI3dyaXRlX2Nzdih0ZXN0LCAib3V0MXBvc3RlcmlvcmFscGhhYW5kYmV0YS5jc3YiKQ0KDQpgYGANCg0KDQokJA0KXGFscGhhIFxzaW0gXHRleHR7VW5pZm9ybX0oMCwwLjUpXFwNClxiZXRhIFxzaW0gTigwLDMxLjYyKVxcDQp5IFxzaW0gXHRleHR7QmVybm91bGxpfShcdGhldGEpXFwNCmxvZ2l0KFx0aGV0YSkgPSBhbHBoYSArIFxiZXRhIFxzdW0gUEZBUw0KJCQNCg0KIyMgSkFHUyBvdXRwdXQgd3JhbmdsaW5nIGZvciBCZXJub3VsbGkgR0xNICANCg0KYGBge3J9DQoNCmNvbnRiIDwtIG91dDIkbWVhbiR0aGV0YVsxXQ0KbG93YiA8LSBvdXQyJG1lYW4kdGhldGFbN10NCm1lZGIgPC0gb3V0MiRtZWFuJHRoZXRhWzE0XQ0KaGlnaGIgPC0gb3V0MiRtZWFuJHRoZXRhWzIxXQ0KDQpjb250YmwgPC0gb3V0MiRxMi41JHRoZXRhWzFdDQpsb3dibCA8LSBvdXQyJHEyLjUkdGhldGFbN10NCm1lZGJsIDwtIG91dDIkcTIuNSR0aGV0YVsxNF0NCmhpZ2hibCA8LSBvdXQyJHEyLjUkdGhldGFbMjFdDQoNCmNvbnRidSA8LSBvdXQyJHE5Ny41JHRoZXRhWzFdDQpsb3didSA8LSBvdXQyJHE5Ny41JHRoZXRhWzddDQptZWRidSA8LSBvdXQyJHE5Ny41JHRoZXRhWzE0XQ0KaGlnaGJ1IDwtIG91dDIkcTk3LjUkdGhldGFbMjFdDQoNCiMjIyBwcm9iYWJpbGl0eSBvZiBhIGZhaWxlZCBuZXN0IChoYXZpbmcgemVybyBoYXRjaGVkIGVnZ3MpDQoNCmZhaWx1cmVkZiA8LSBkYXRhLmZyYW1lKA0KICBkb3NlPWMoMC4wMDAxMjEsIDAuMTIxLCAwLjQ1LCAyLjA0KSwNCiAgbWVhbj1jKGNvbnRiLCBsb3diLCBtZWRiLCBoaWdoYiksDQogIGxvd2VyPWMoY29udGJsLCBsb3dibCwgbWVkYmwsIGhpZ2hibCksDQogIHVwcGVyPWMoY29udGJ1LCBsb3didSwgbWVkYnUsIGhpZ2hidSkNCikNCg0KDQoNCiMgcGxvdChqaXR0ZXIoZGZsb25nZm9yY291bnQkZmFpbHVyZSwgMC4yKX5qaXR0ZXIoYXMubnVtZXJpYyhmYWN0b3IoZGZsb25nZm9yY291bnQkZG9zZW51bSkpLDAuNSksIGF4ZXM9RiwgcGNoPTMsIHlsYWI9IlBlciBuZXN0IHByb2JhYmlsaXR5IG9mIGZhaWx1cmUiLCB4bGFiPSJEaWV0IGNvbmNlbnRyYXRpb24gKG1nL2tnLWQgc3VtUEZBUykiLCApDQojIGxpbmVzKGFzLm51bWVyaWMoZmFjdG9yKGRmbG9uZ2ZvcmNvdW50JGRvc2VudW0pKSwgb3V0MiRtZWFuJHRoZXRhLCBjb2w9ImJsdWUiLCBsd2Q9MykNCiMgbGluZXMoYXMubnVtZXJpYyhmYWN0b3IoZGZsb25nZm9yY291bnQkZG9zZW51bSkpLCBvdXQyJHEyLjUkdGhldGEsIGx3ZD0zLCBsdHk9MikNCiMgbGluZXMoYXMubnVtZXJpYyhmYWN0b3IoZGZsb25nZm9yY291bnQkZG9zZW51bSkpLCBvdXQyJHE5Ny41JHRoZXRhLCBsd2Q9MywgbHR5PTIpDQojIGF4aXMoMSxhdD11bmlxdWUoYXMubnVtZXJpYyhmYWN0b3IoZGZsb25nZm9yY291bnQkZG9zZW51bSkpKSwgbGFiZWxzPXNvcnQodW5pcXVlKHJvdW5kKGRmbG9uZ2ZvcmNvdW50JGRvc2VudW0sMikpKSkNCiMgYXhpcygyLGxhcz0xKQ0KDQpgYGANCg0KDQoNCg0KDQoNCiMjIFBsb3Qgb2YgcHJlZGljdGVkIHByb2JhYmlsaXR5IG9mIGZhaWx1cmUgKHplcm8gaGF0Y2hlZCBlZ2dzKSAgDQoNCmBgYHtyLCBwcm9iYWJpbGl0eW9mZmFpbHVyZWRvc2VyZXNwb25zZSwgZmlnLnBhdGg9J2ZpZ3VyZXMvJyxkZXY9YygncG5nJywgJ3RpZmYnLCAnanBlZycpLCBkcGk9MzAwLCBmaWcuaGVpZ2h0PTYsIGZpZy53aWR0aD02fQ0KDQpwYXIobWFpPWMoMiwxLjIsMC4xLDAuMykpDQpwbG90KGppdHRlcihmYWlsdXJlLCAwLjUpfmppdHRlcihhcy5udW1lcmljKGZhY3Rvcihkb3NlKSkpLCBkYXRhPWRmbG9uZ2ZvcmNvdW50LCBwY2g9MywgeWxhYj0iUHJvYmFiaWxpdHkgb2YgbmVzdCBmYWlsdXJlIiwgeGxhYj1leHByZXNzaW9uKEFkdWx0fmRhaWx5fmRvc2V+bWcva2d+U2lnbWEqUEZBUyksDQogICAgIGJ0eT0ibiIsIGxhcz0xLCBheGVzPUYsIGNleC5sYWI9MS41KQ0KYXhpcygxLCBhdD1jKDEsMiwzLDQpLCBsYWJlbHM9YygiMC4wMDAxMjEiLCAiMC4xMjEiLCAiMC40NSIsICIyLjA0IiksIGZvbnQ9MSwgY2V4LmF4aXM9MS41KQ0KYXhpcygyLCBhdD1jKDAsMC41LDEpLCBsYWJlbHM9YygwLDAuNSwxKSwgZm9udD0xLCBsYXM9MSwgY2V4LmF4aXM9MS41KQ0KYXJyb3dzKGFzLm51bWVyaWMoZmFjdG9yKGZhaWx1cmVkZiRkb3NlKSksZmFpbHVyZWRmJGxvd2VyLGFzLm51bWVyaWMoZmFjdG9yKGZhaWx1cmVkZiRkb3NlKSksZmFpbHVyZWRmJHVwcGVyLCBsd2Q9MiwgbGVuZ3RoPTAuMSwgYW5nbGU9OTAsIGNvZGU9MywgY29sPWMoImRhcmtncmVlbiIsImJsdWUiLCJkYXJrb3JhbmdlIiwicmVkIikpDQpwb2ludHMobWVhbn5hcy5udW1lcmljKGZhY3Rvcihkb3NlKSksIGRhdGE9ZmFpbHVyZWRmLCB0eXBlPSJsIiwgY29sPSJkYXJrZ3JheSIsIGx3ZD0yKQ0KcG9pbnRzKG1lYW5+YXMubnVtZXJpYyhmYWN0b3IoZG9zZSkpLCBkYXRhPWZhaWx1cmVkZiwgdHlwZT0icCIsIGNvbD1jKCJkYXJrZ3JlZW4iLCJibHVlIiwiZGFya29yYW5nZSIsInJlZCIpLCBwY2g9MTYsIGNleD0xLjUpDQpwb2ludHMoYygwLjk1LDEuMDUpLGMoMCwwKSxjb2w9InB1cnBsZSIsIHBjaD0yKQ0KYXhpcygxLCBhdD1jKDEsMiwzLDQpLCBsYWJlbHM9YygiMC4wMDMiLCAiMy4zNSIsICI4LjM0IiwgIjY1Ljg0IiksIGZvbnQ9MSwgY2V4LmF4aXM9MS41LCBsaW5lPTUpDQptdGV4dChleHByZXNzaW9uKE1lYW5+ZWdnfm1nL2tnflNpZ21hKlBGQVMpLCBzaWRlPTEsIGxpbmU9OCwgZm9udD0xLCBjZXg9MS41KQ0KDQoNCmBgYA0KDQoNCiMgSW50ZXJwb2xhdGUgYWR2ZXJzZSBpbmNyZWFzZSBpbiBwcm9iYWJpbGl0eSBvZiBuZXN0IGZhaWx1cmUgdXNpbmcgQmVybm91bGxpIEdMTSAgDQoNClVzaW5nIHRoZSBwb3N0ZXJpb3IgZHJhd3MsIGZpbmQgdGhlIGRvc2VzIGJyYWNrZXRpbmcgOTUlIHByb2JhYmlsaXR5IG9mIG9ic2VydmluZyB0aGF0IGFtb3VudCBvZiBuZXN0IGZhaWx1cmUuICANCg0KIyMgQmFja2dyb3VuZCBwcm9iYWJpbGl0eSBvZiBoYXZpbmcgemVybyBoYXRjaGVkIGVnZ3MgIA0KDQpgYGB7cn0NCg0KZGJpbm9tKDEsMSxwcm9iPWNvbnRiKQ0KDQpgYGANCg0KIyMgMC4yIGFkZGVkIHJpc2sgb2YgaGF2aW5nIHplcm8gaGF0Y2hlZCBlZ2dzICANCg0KYGBge3J9DQoNCmRiaW5vbSgxLDEscHJvYj1jb250YikrMC4yDQoNCmBgYA0KDQoNCiMjIEhpZ2hlc3QgY29uY2VudHJhdGlvbiB3aGVyZSBwcm9iYWJpbGl0eSBvZiBoYXZpbmcgemVybyBlZ2dzIGlzIDwwLjI4ICANCg0KaS5lLiAic2FmZSIgY29uY2VudHJhdGlvbg0KDQpgYGB7cn0NCg0KIyMjIGRvIHByZWRpY3Rpb24gaW50ZXJwb2xhdGlvbiBmb3IgaGF2aW5nIHplcm8NCg0KYWx0LmNvbmMucHJlZCA8LSBzZXEoZnJvbT0wLjAwMDEsdG89MywgbGVuZ3RoLm91dD0xMDAwKQ0KcHJlZDMgPC0gYXJyYXkoTkEsZGltPWMobGVuZ3RoKGFsdC5jb25jLnByZWQpLDEyMDAwKSkNCmZvcihpIGluIDE6MTIwMDApew0KICBwcmVkM1ssaV0gPC0gcGxvZ2lzKG91dDIkc2ltcy5saXN0JGFscGhhW2ldK291dDIkc2ltcy5saXN0JGJldGFbaV0qYWx0LmNvbmMucHJlZCkNCn0NCg0KcG0zIDwtIGFwcGx5KHByZWQzLDEsIG1lYW4pDQpwbTNsIDwtIGFwcGx5KHByZWQzLDEsIHF1YW50aWxlLCBwcm9icz0wLjk3NSkNCnBtM3UgPC0gYXBwbHkocHJlZDMsMSwgcXVhbnRpbGUsIHByb2JzPTAuMDI1KQ0KDQpwcm9iMiA8LSBhcHBseShwcmVkMywgMSwgZnVuY3Rpb24oeCkgbWVhbigoeC0xKTwwKSkNCg0KZHByb2IwMiA8LSBhcHBseShwcmVkMywxLGZ1bmN0aW9uKHgpIG1lYW4oZGJpbm9tKDEsMSxwcm9iPXgpKSkNCmRwcm9iMDJtaW4gPC0gYXBwbHkocHJlZDMsMSxmdW5jdGlvbih4KSBxdWFudGlsZShkYmlub20oMSwxLHByb2I9eCksIHByb2JzPTAuMDUpKQ0KZHByb2IwMm1heCA8LSBhcHBseShwcmVkMywxLGZ1bmN0aW9uKHgpIHF1YW50aWxlKGRiaW5vbSgxLDEscHJvYj14KSwgcHJvYnM9MC45NSkpDQoNCiNwbG90KGRwcm9iMH5hbHQuY29uYy5wcmVkLCB5bGltPWMoMCwxKSkNCiNwb2ludHMoZHByb2IwbWlufmFsdC5jb25jLnByZWQsIGNvbD0iZGFya2dyYXkiKQ0KI3BvaW50cyhkcHJvYjBtYXh+YWx0LmNvbmMucHJlZCwgY29sPSJkYXJrZ3JheSIpDQoNCg0KbWludHdlbnR5dGhyZXNob2xkMiA8LSBtYXgoYWx0LmNvbmMucHJlZFtkcHJvYjAybWluPDAuNTU3OTc2Nl0pDQptYXh0d2VudHl0aHJlc2hvbGQyIDwtIG1heChhbHQuY29uYy5wcmVkW2Rwcm9iMDJtYXg8MC41NTc5NzY2XSkNCm1lYW50d2VudHl0aHJlc2hvbGQyIDwtIG1heChhbHQuY29uYy5wcmVkW2Rwcm9iMDI8MC41NTc5NzY2XSkNCm1pbnR3ZW50eXRocmVzaG9sZDINCm1lYW50d2VudHl0aHJlc2hvbGQyDQptYXh0d2VudHl0aHJlc2hvbGQyDQoNCmBgYA0KDQoNCmBgYHtyLCBpbnRlcnBvbGF0ZWRwcm9iYWJpbGl0eW9mbmVzdGZhaWx1cmUsIGZpZy5wYXRoPSdmaWd1cmVzLycsZGV2PWMoJ3BuZycsICd0aWZmJywgJ2pwZWcnKSwgZHBpPTMwMCwgZmlnLmhlaWdodD01LjYsIGZpZy53aWR0aD03fQ0KDQpwYXIobWFpPWMoMS4yLDEuMiwwLjEsMC43NSkpDQpwbG90KGRwcm9iMDJ+YWx0LmNvbmMucHJlZCwgbG9nPSIiLCB5bGltPWMoMCwxKSwgdHlwZT0ibCIsIGJ0eT0ibiIsIHhsaW09YygtMC4yNSwzKSwNCiAgICAgeWxhYj0iUHJvYmFiaWxpdHkgb2YgbmVzdCBmYWlsdXJlIiwgeGxhYj1leHByZXNzaW9uKHBhc3RlKCJBZHVsdCBkYWlseSBkb3NlICIsIFNpZ21hLCJQRkFTIG1nL2tnIikpLCBsYXM9MSwNCiAgICAgZm9udD0xLCBmb250LmxhYj0xLCBwY2g9MTYsIGNleD0yLCBsd2Q9MiwgY2V4LmxhYj0xLjUsIGNleC5heGlzPTEuNSkNCnBvaW50cyhkcHJvYjAybWlufmFsdC5jb25jLnByZWQsIHR5cGU9ImwiLCBsdHk9MiwgY29sPSJkYXJrZ3JheSIsIGx3ZD0yKQ0KcG9pbnRzKGRwcm9iMDJtYXh+YWx0LmNvbmMucHJlZCwgdHlwZT0ibCIsIGx0eT0yLCBjb2w9ImRhcmtncmF5IiwgbHdkPTIpDQphYmxpbmUoaD1jKDAsMSkpDQp0ZXh0KC0wLjM1LGRiaW5vbSgxLDEscHJvYj1jb250YiksIjAuMzYiLCBwb3M9NCwgY29sPSJkYXJrZ3JlZW4iKQ0KdGV4dCgtMC4zNSxkYmlub20oMSwxLHByb2I9Y29udGIpKzAuMiwiMC41NiIsIHBvcz00LCBjb2w9InJlZCIpDQpzZWdtZW50cygwLGRiaW5vbSgxLDEscHJvYj1jb250YikrMC4yLDMsZGJpbm9tKDEsMSxwcm9iPWNvbnRiKSswLjIsIGNvbD0icmVkIikNCnNlZ21lbnRzKDAuMzUxNDM5NiwwLjU2LDAuMzUxNDM5NiwwLjY2LCBjb2w9ImJsYWNrIikNCnRleHQoMC4zNTE0Mzk2LDAuNjYsIjAuMzUgbWcva2ciLCBwb3M9MywgY29sPSJibGFjayIpDQpzZWdtZW50cygzLDAuNTYsMywwLjI2LCBjb2w9ImJsYWNrIikNCnRleHQoMi45MTU5MTksMC4yNiwiMi45MiBtZy9rZyIsIHBvcz0xLCBjb2w9ImJsYWNrIiwgeHBkPU5BKQ0Kc2VnbWVudHMoMC44OTE5NjIyLDAuNTYsMC44OTE5NjIyLDAuMzYsIGNvbD0iYmxhY2siKQ0KdGV4dCgwLjg5MTk2MjIsMC4zNiwiMC44OSBtZy9rZyIsIHBvcz0xLCBjb2w9ImJsYWNrIiwgeHBkPU5BKQ0KDQpgYGANCg0KDQoNCiMgU3RvY2hhc3RpYyBwb3B1bGF0aW9uIHRyYWplY3RvcmllcyAgDQoNCiMjIFNpbXBsZSBtb2RlbCBkaWFncmFtICANCg0KYGBge3IsIGZpZy5oZWlnaHQ9Nywgd2lkdGg9N30NCg0KDQptZXJtYWlkKCINCiAgZ3JhcGggUkwNCiAgICBBKEFkdWx0KTsNCiAgICBKKEp1dmVuaWxlKTsNCiAgICBJKEltbWlncmF0aW9uKTsNCiAgICANCiAgICBBLS1GZWN1bmRpdHktLT5KOw0KICAgIEEtLUFkdWx0IFN1cnZpdmFsLS0+QTsNCiAgICBKLS1KdXZlbmlsZSBTdXJ2aXZhbC0tPkE7DQogICAgSS0tPkE7DQoiLCANCndpZHRoPTUwMCwgaGVpZ2h0PTUwMCkNCmBgYA0KDQoNCg0KDQoNCiMjIEJ1aWxkIGRpc3RyaWJ1dGlvbnMgZm9yIGRlbW9ncmFwaGljIHJhdGVzICANCg0KU3Vydml2YWwgYW5kIGltbWlncmF0aW9uIHJhdGVzIGZyb20gTWNDbHVyZSBldCBhbC4gMjAyMS4NCk1jQ2x1cmUgQ0pXIGV0IGFsLiAyMDIxLiBEZW1vZ3JhcGh5IG9mIGEgd2lkZXNwcmVhZCByYXB0b3IgYWNyb3NzIGRpc3BhcmF0ZSByZWdpb25zLiBJYmlzLiAxNjMoMik6NjU44oCTNjcwIGh0dHBzOi8vZG9pLm9yZy8xMC4xMTExL2liaS4xMjkxNg0KDQojIyMgSnV2ZW5pbGUgc3Vydml2YWwgIA0KDQpgYGB7cn0NCmp1dnN1cnZkaXN0IDwtIGMoDQogIHJub3JtKDEwMDAsIG1lYW49MC4xMywgc2Q9MC4wNiksDQogIHJub3JtKDEwMDAsIG1lYW49MC4xNSwgc2Q9MC4wNSksDQogIHJub3JtKDEwMDAsIG1lYW49MC4wOSwgc2Q9MC4wMyksDQogIHJub3JtKDEwMDAsIG1lYW49MC4wOCwgc2Q9MC4wNikNCikNCmp1dnN1cnZkaXN0IDwtIGp1dnN1cnZkaXN0WyFqdXZzdXJ2ZGlzdDwwXQ0KcGFyKG1mcm93PWMoMSwyKSxtYWk9YygwLjgsMC44LDAuMSwwLjEpKQ0KaGlzdChqdXZzdXJ2ZGlzdCwgbWFpbj0iIikNCnBsb3QoZGVuc2l0eShqdXZzdXJ2ZGlzdCksIG1haW49IiIsYnR5PSJuIikNCnBhcihtZnJvdz1jKDEsMSksbWFpPWMoMSwxLDAuNSwwLjUpKQ0Kc3VtbWFyeShqdXZzdXJ2ZGlzdCkNCnNkKGp1dnN1cnZkaXN0KQ0KYGBgDQoNCiMjIyMgSnV2ZW5pbGUgc3Vydml2YWwgdmFyaWFiaWxpdHkgIA0KDQpBY3Jvc3MgdGhlIHBvcHVsYXRpb25zLiAgDQoNCmBgYHtyfQ0KDQpzZChjKDAuMTMsIDAuMTUsIDAuMDksIDAuMDgpKQ0KDQpgYGANCg0KIyMjIEFkdWx0IHN1cnZpdmFsICANCg0KYGBge3J9DQphZHRzdXJ2ZGlzdCA8LSBjKA0KICBybm9ybSgxMDAwLCBtZWFuPTAuNTAsIHNkPTAuMDMpLA0KICBybm9ybSgxMDAwLCBtZWFuPTAuNDgsIHNkPTAuMDMpLA0KICBybm9ybSgxMDAwLCBtZWFuPTAuNTUsIHNkPTAuMDMpLA0KICBybm9ybSgxMDAwLCBtZWFuPTAuNTYsIHNkPTAuMDgpDQopDQojYWR0c3VydmRpc3QgPC0gYWR0c3VydmRpc3RbYWR0c3VydmRpc3Q+MF0NCnBhcihtZnJvdz1jKDEsMiksbWFpPWMoMC44LDAuOCwwLjEsMC4xKSkNCmhpc3QoYWR0c3VydmRpc3QsIG1haW49IiIpDQpwbG90KGRlbnNpdHkoYWR0c3VydmRpc3QpLCBtYWluPSIiLGJ0eT0ibiIpDQpwYXIobWZyb3c9YygxLDEpLG1haT1jKDEsMSwwLjUsMC41KSkNCnN1bW1hcnkoYWR0c3VydmRpc3QpDQpzZChhZHRzdXJ2ZGlzdCkNCmBgYA0KDQojIyMjIEFkdWx0IHN1cnZpdmFsIHZhcmlhYmlsaXR5ICANCg0KYGBge3J9DQoNCnNkKGMoMC41MCwgMC40OCwgMC41NSwgMC41NikpDQoNCmBgYA0KDQojIyMgSW1taWdyYXRpb24gIA0KDQpgYGB7cn0NCmltbWlkaXN0IDwtIGMoDQogIHJub3JtKDEwMDAsIG1lYW49MC4yMSwgc2Q9MC4wNiksDQogIHJub3JtKDEwMDAsIG1lYW49MC4yMSwgc2Q9MC4wNSksDQogIHJub3JtKDEwMDAsIG1lYW49MC4xNSwgc2Q9MC4wNCksDQogIHJub3JtKDEwMDAsIG1lYW49MC4yMCwgc2Q9MC4wOSkNCikNCmltbWlkaXN0IDwtIGltbWlkaXN0WyFpbW1pZGlzdDwwXQ0KcGFyKG1mcm93PWMoMSwyKSxtYWk9YygwLjgsMC44LDAuMSwwLjEpKQ0KaGlzdChpbW1pZGlzdCwgbWFpbj0iIikNCnBsb3QoZGVuc2l0eShpbW1pZGlzdCksIG1haW49IiIsYnR5PSJuIikNCnBhcihtZnJvdz1jKDEsMSksbWFpPWMoMSwxLDAuNSwwLjUpKQ0Kc3VtbWFyeShpbW1pZGlzdCkNCnNkKGltbWlkaXN0KQ0KYGBgDQoNCiMjIyMgSW1taWdyYXRpb24gdmFyaWFiaWxpdHkgIA0KDQpgYGB7cn0NCg0Kc2QoYygwLjIxLCAwLjIxLCAwLjE1LCAwLjIwKSkNCg0KYGBgDQoNCiMjIyBGZWN1bmRpdHkgIA0KDQpgYGB7cn0NCmZlY3VuZGRpc3QgPC0gYygNCiAgcm5vcm0oMTAwMCwgbWVhbj0xLjU1LCBzZD0wLjEzKSwNCiAgcm5vcm0oMTAwMCwgbWVhbj0xLjM2LCBzZD0wLjA1KSwNCiAgcm5vcm0oMTAwMCwgbWVhbj0xLjM4LCBzZD0wLjA2KSwNCiAgcm5vcm0oMTAwMCwgbWVhbj0xLjMyLCBzZD0wLjEzKQ0KKQ0KI2ZlY3VuZGRpc3QgPC0gZmVjdW5kZGlzdFshZmVjdW5kZGlzdDwwXQ0KcGFyKG1mcm93PWMoMSwyKSxtYWk9YygwLjgsMC44LDAuMSwwLjEpKQ0KaGlzdChmZWN1bmRkaXN0LCBtYWluPSIiKQ0KcGxvdChkZW5zaXR5KGZlY3VuZGRpc3QpLCBtYWluPSIiLGJ0eT0ibiIpDQpwYXIobWZyb3c9YygxLDEpLG1haT1jKDEsMSwwLjUsMC41KSkNCnN1bW1hcnkoZmVjdW5kZGlzdCkNCnNkKGZlY3VuZGRpc3QpDQpgYGANCg0KIyMjIyBGZWN1bmRpdHkgdmFyaWFiaWxpdHkgIA0KDQpgYGB7cn0NCg0Kc2QoYygxLjU1LCAxLjM2LCAxLjM4LCAxLjMyKSkNCg0KYGBgDQoNCg0KDQoNCg0KDQojIHRyaWFsIHJ1biB1c2luZyBDaGFwdGVyLlNlY3Rpb24gMy4zIGZyb20gSVBNIGJvb2sgIA0KDQojIyAzLjMgQ2xhc3NpY2FsIGFuYWx5c2lzIG9mIGEgbWF0cml4IHBvcHVsYXRpb24gbW9kZWwgIA0KDQojIyMgMy4zLg0KDQojIyMgMy4zLjUgQW5hbHlzaXMgb2YgYSBtYXRyaXggcG9wdWxhdGlvbiBtb2RlbCB3aXRoIGRpZmZlcmVudCBzb3VyY2VzIG9mIHN0b2NoYXN0aWNpdHkgYW5kIHBhcmFtZXRlciB1bmNlcnRhaW50eSAgDQoNClNlZSBodHRwczovL2dpdGh1Yi5jb20vbWlrZW1lcmVkaXRoL0lQTV9jb2RlL2Jsb2IvbWFpbi9JUE1fMDMvSVBNXzAzLjMuNS5SDQoNCkNvZGUgaGFzIGJlZW4gbW9kaWZpZWQgc28gInRlbXBvcmFsIiBzdG9jaGFzdGljaXR5IGlzIHJlcGxhY2VkIHdpdGggInBvcHVsYXRpb24iIHN0b2NoYXN0aWNpdHkgYmFzZWQgb24gdGhlIDQgcG9wdWxhdGlvbnMgaW4gTWNjbHVyZSBldCBhbC4gMjAyMS4gIA0KDQojIyMjIFIgc3R1ZmYgdG8gbWFrZSBpdCBoYXBwZW4sIGJvcnJvd2VkIGZyb20gSVBNIGJvb2sgcGFja2FnZSAgDQoNCmBgYHtyfQ0KIyBodHRwczovL2dpdGh1Yi5jb20va2Vua2VsbG5lci9JUE1ib29rL2Jsb2IvbWFpbi9SL3N0b3BpZm5vdC5SDQoNCnN0b3BpZm5vdFByb2JhYmlsaXR5IDwtIGZ1bmN0aW9uKGFyZywgYWxsb3dOQT1GQUxTRSkgew0KICBuYW1lIDwtIGRlcGFyc2Uoc3Vic3RpdHV0ZShhcmcpKQ0KICBpZihhbGxvd05BICYmIGFsbChpcy5uYShhcmcpKSkgeyAgIyBBbiBhbGwtTkEgdmVjdG9yIGlzIGxvZ2ljYWwsIGJ1dCBvay4NCiAgICAjIGRvIG5vdGhpbmcNCiAgfSBlbHNlIHsNCiAgICBpZighYWxsb3dOQSAmJiBhbnkoaXMubmEoYXJnKSkpDQogICAgICBzdG9wKCJBcmd1bWVudCAnIiwgbmFtZSwgIicgbXVzdCBub3QgY29udGFpbiBOQSBvciBOYU4uIiwgY2FsbC49RkFMU0UpDQogICAgaWYoIWlzLm51bWVyaWMoYXJnKSkNCiAgICAgIHN0b3AoIkFyZ3VtZW50ICciLCBuYW1lLCAiJyBtdXN0IGJlIG51bWVyaWMuIiwgY2FsbC49RkFMU0UpDQogICAgaWYoYW55KGFyZyA8IDAgfCBhcmcgPiAxLCBuYS5ybT1UUlVFKSkgew0KICAgICAgaWYoYWxsb3dOQSkgew0KICAgICAgICBzdG9wKCJBcmd1bWVudCAnIiwgbmFtZSwgIicgbXVzdCBiZSBhIHByb2JhYmlsaXR5IGJldHdlZW4gMCBhbmQgMSwgb3IgTkEuIiwgY2FsbC49RkFMU0UpDQogICAgICB9IGVsc2Ugew0KICAgICAgICBzdG9wKCJBcmd1bWVudCAnIiwgbmFtZSwgIicgbXVzdCBiZSBhIHByb2JhYmlsaXR5IGJldHdlZW4gMCBhbmQgMS4iLCBjYWxsLj1GQUxTRSkNCiAgICAgIH0NCiAgICB9DQogIH0NCn0NCg0Kc3RvcGlmTmVnYXRpdmUgPC0gZnVuY3Rpb24oYXJnLCBhbGxvd05BPUZBTFNFLCBhbGxvd1plcm89VFJVRSkgew0KICBuYW1lIDwtIGRlcGFyc2Uoc3Vic3RpdHV0ZShhcmcpKQ0KICBpZihhbGxvd05BICYmIGFsbChpcy5uYShhcmcpKSkgeyAgIyBBbiBhbGwtTkEgdmVjdG9yIGlzIGxvZ2ljYWwsIGJ1dCBvay4NCiAgICAjIGRvIG5vdGhpbmcNCiAgfSBlbHNlIHsNCiAgICBpZighYWxsb3dOQSAmJiBhbnkoaXMubmEoYXJnKSkpDQogICAgICBzdG9wKCJBcmd1bWVudCAnIiwgbmFtZSwgIicgbXVzdCBub3QgY29udGFpbiBOQSBvciBOYU4uIiwgY2FsbC49RkFMU0UpDQogICAgaWYoIWlzLm51bWVyaWMoYXJnKSkNCiAgICAgIHN0b3AoIkFyZ3VtZW50ICciLCBuYW1lLCAiJyBtdXN0IGJlIG51bWVyaWMuIiwgY2FsbC49RkFMU0UpDQogICAgaWYoYWxsb3daZXJvKSB7DQogICAgICBpZihhbnkoYXJnIDwgMCwgbmEucm09VFJVRSkpIHsNCiAgICAgICAgaWYoYWxsb3dOQSkgew0KICAgICAgICAgIHN0b3AoIkFyZ3VtZW50ICciLCBuYW1lLCAiJyBtdXN0IGJlIG5vbi1uZWdhdGl2ZSwgb3IgTkEuIiwgY2FsbC49RkFMU0UpDQogICAgICAgIH0gZWxzZSB7DQogICAgICAgICAgc3RvcCgiQXJndW1lbnQgJyIsIG5hbWUsICInIG11c3QgYmUgbm9uLW5lZ2F0aXZlLiIsIGNhbGwuPUZBTFNFKQ0KICAgICAgICB9DQogICAgICB9DQogICAgfSBlbHNlIHsNCiAgICAgIGlmKGFueShhcmcgPD0gMCwgbmEucm09VFJVRSkpIHsNCiAgICAgICAgaWYoYWxsb3dOQSkgew0KICAgICAgICAgIHN0b3AoIkFyZ3VtZW50ICciLCBuYW1lLCAiJyBtdXN0IGJlIGdyZWF0ZXIgdGhhbiAwLCBvciBOQS4iLCBjYWxsLj1GQUxTRSkNCiAgICAgICAgfSBlbHNlIHsNCiAgICAgICAgICBzdG9wKCJBcmd1bWVudCAnIiwgbmFtZSwgIicgbXVzdCBiZSBncmVhdGVyIHRoYW4gMC4iLCBjYWxsLj1GQUxTRSkNCiAgICAgICAgfQ0KICAgICAgfQ0KICAgIH0NCiAgfQ0KfQ0KDQojIGh0dHBzOi8vZ2l0aHViLmNvbS9rZW5rZWxsbmVyL0lQTWJvb2svYmxvYi9tYWluL1Ivc3RvcGlmbm90LlINCg0KIyBodHRwczovL2dpdGh1Yi5jb20va2Vua2VsbG5lci9JUE1ib29rL2Jsb2IvbWFpbi9SL0JldGFEaXN0LlINCg0KZ2V0QmV0YTJQYXIgPC0gZnVuY3Rpb24obWVhbiwgc2QpIHsNCiAgc3RvcGlmbm90UHJvYmFiaWxpdHkobWVhbiwgYWxsb3dOQT1GQUxTRSkNCiAgc3RvcGlmTmVnYXRpdmUoc2QsIGFsbG93TkE9RkFMU0UsIGFsbG93WmVybz1GQUxTRSkNCg0KICBudSA8LSBtZWFuICogKDEtbWVhbikgLyBzZF4yIC0gMQ0KICBpZihhbnkobnUgPD0gMCkpIHsNCiAgICB3YXJuaW5nKCJzZCBpcyB0b28gbGFyZ2U7IHNvbWUgc2hhcGUgcGFyYW1ldGVycyB3aWxsIGJlIE5BLiIsIGNhbGwuPUZBTFNFKQ0KICAgIG51W251IDw9IDBdIDwtIE5BDQogIH0NCiAgYWxwaGEgPC0gbWVhbiAqIG51DQogIGJldGEgPC0gKDEtbWVhbikgKiBudQ0KICBjYmluZChzaGFwZTE9YWxwaGEsIHNoYXBlMj1iZXRhKQ0KfQ0KDQpkYmV0YTIgPC0gZnVuY3Rpb24oeCwgbWVhbiwgc2QpIHsNCiAgc2hhcGVzIDwtIGdldEJldGEyUGFyKG1lYW4sc2QpDQogIHJldHVybihkYmV0YSh4LCBzaGFwZXNbLDFdLCBzaGFwZXNbLDJdKSkNCn0NCg0KcGJldGEyIDwtIGZ1bmN0aW9uKHEsIG1lYW4sIHNkLCBsb3dlci50YWlsPVRSVUUsIGxvZy5wPUZBTFNFKSB7DQogIHNoYXBlcyA8LSBnZXRCZXRhMlBhcihtZWFuLHNkKQ0KICByZXR1cm4ocGJldGEocSwgc2hhcGVzWywxXSwgc2hhcGVzWywyXSwgbG93ZXIudGFpbD1sb3dlci50YWlsLCBsb2cucD1sb2cucCkpDQp9DQpxYmV0YTIgPC0gZnVuY3Rpb24ocCwgbWVhbiwgc2QsIGxvd2VyLnRhaWw9VFJVRSwgbG9nLnA9RkFMU0UpIHsNCiAgc2hhcGVzIDwtIGdldEJldGEyUGFyKG1lYW4sc2QpDQogIHJldHVybihxYmV0YShwLCBzaGFwZXNbLDFdLCBzaGFwZXNbLDJdLCBsb3dlci50YWlsPWxvd2VyLnRhaWwsIGxvZy5wPWxvZy5wKSkNCn0NCg0KcmJldGEyIDwtIGZ1bmN0aW9uKG4sIG1lYW4sIHNkKSB7DQogIHNoYXBlcyA8LSBnZXRCZXRhMlBhcihtZWFuLHNkKQ0KICByZXR1cm4ocmJldGEobiwgc2hhcGVzWywxXSwgc2hhcGVzWywyXSkpDQp9DQoNCiMgaHR0cHM6Ly9naXRodWIuY29tL2tlbmtlbGxuZXIvSVBNYm9vay9ibG9iL21haW4vUi9CZXRhRGlzdC5SDQoNCg0KYGBgDQoNCg0KIyMjIyBBY3R1YWwgc2ltdWxhdGlvbnMgIA0KDQoNCmBgYHtyLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTB9DQoNCiMgaHR0cHM6Ly9naXRodWIuY29tL21pa2VtZXJlZGl0aC9JUE1fY29kZS9ibG9iL21haW4vSVBNXzAzL0lQTV8wMy4zLjUuUg0KDQojIDMuMyBDbGFzc2ljYWwgYW5hbHlzaXMgb2YgYSBtYXRyaXggcG9wdWxhdGlvbiBtb2RlbA0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KIyAzLjMuNSBBbmFseXNpcyBvZiBhIG1hdHJpeCBwb3B1bGF0aW9uIG1vZGVsIHdpdGggZGlmZmVyZW50IHNvdXJjZXMgb2YNCiMgICAgICAgc3RvY2hhc3RpY2l0eSBhbmQgcGFyYW1ldGVyIHVuY2VydGFpbnR5DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIERlZmluZSBtZWFuLCBtZWFzdXJlbWVudCBlcnJvciBhbmQgdGVtcG9yYWwgdmFyaWFiaWxpdHkgb2YgdGhlIGRlbW9ncmFwaGljIHBhcmFtZXRlcnMNCm1lYW4uc2ogPC0gMC4xMTYzNjE1ICAgICAgICAgICMgTWVhbiB2YWx1ZSBvZiBqdXYuIHN1cnZpdmFsDQpzZC5zai5lIDwtIDAuMDU1NDU4OCAgICAgICAgIyBVbmNlcnRhaW50eSBvZiBtZWFuIGp1di4gc3Vydml2YWwgYXMgU0Qgb24gbmF0dXJhbCBzY2FsZQ0Kc2Quc2oudCA8LSBwbG9naXMoMC4wMzMwNDAzOCkgICAgICAgICAjIHBvcHVsYXRpb24gdmFyaWFiaWxpdHkgb2YganV2LiBzdXJ2aXZhbCBhcyBTRCBvbiBsb2dpdCBzY2FsZSAjIEFuZHJldywgdGhpcyBtaWdodCBoYXZlIHRvIGJlIHBsb2dpcygwLjAzMzA0MDM4KSwgYnV0IG5vdCBzdXJlLCBjaGVjayB0aGUgdGV4dC4NCm1lYW4uc2EgPC0gMC41MjIyICAgICAgICAgIyBNZWFuIHZhbHVlIG9mIGFkLiBzdXJ2aXZhbA0Kc2Quc2EuZSA8LSAwLjA1NzY5NjkzICAgICAgICAjIFVuY2VydGFpbnR5IG9mIG1lYW4gYWQuIHN1cnZpdmFsIGFzIFNEIG9uIG5hdHVyYWwgc2NhbGUNCnNkLnNhLnQgPC0gcGxvZ2lzKDAuMDM4NjIyMSkgICAgICAgICAjIFRlbXBvcmFsIHZhcmlhYmlsaXR5IG9mIGFkLiBzdXJ2aXZhbCBhcyBTRCBvbiBsb2dpdCBzY2FsZQ0KbWVhbi5mMSA8LSAxLjQwMzUgICAgICAgICAgIyBNZWFuIHZhbHVlIG9mIHByb2R1Y3Rpdml0eSBvZiAxeSBmZW1hbGVzDQpzZC5mMS5lIDwtIDAuMTMyNjAzMiAgICAgICAgICMgVW5jZXJ0YWludHkgb2YgbWVhbiBwcm9kdWN0aXZpdHkgYXMgU0Qgb24gbmF0dXJhbCBzY2FsZQ0Kc2QuZjEudCA8LSAwLjEwMTQ0NzkgICAgICAgICAgIyBUZW1wb3JhbCB2YXJpYWJpbGl0eSBvZiBwcm9kdWN0aXZpdHkgYXMgU0Qgb24gbmF0dXJhbCBzY2FsZQ0KbWVhbi5mYSA8LSAxLjQwMzUgICAgICAgICAgIyBNZWFuIHZhbHVlIG9mIHByb2R1Y3Rpdml0eSBvZiBhZHVsdCBmZW1hbGVzDQpzZC5mYS5lIDwtIDAuMTMyNjAzMiAgICAgICAgICMgVW5jZXJ0YWludHkgb2YgbWVhbiBwcm9kdWN0aXZpdHkgYXMgU0Qgb24gbmF0dXJhbCBzY2FsZQ0Kc2QuZmEudCA8LSAwLjEwMSAgICAgICAgICAjIFRlbXBvcmFsIHZhcmlhYmlsaXR5IG9mIHByb2R1Y3Rpdml0eSBhcyBTRCBvbiBuYXR1cmFsIHNjYWxlDQptZWFuLmltbSA8LSAwLjE5MjU4NyAgICAgICMgTWVhbiB2YWx1ZSBvZiBhZHVsdCBpbW1pZ3JhdGlvbiAgDQpzZC5pbW0uZSA8LSAwLjA2Njc0ODA5ICAgICMgVW5jZXJ0YWludHkgb2YgbWVhbiBhZHVsdCBpbW1pZ3JhdGlvbiBhcyBTRCBvbiBuYXR1cmFsIHNjYWxlDQpzZC5pbW0udCA8LSAwLjAyODcyMjgxICAgICMgcG9wdWxhdGlvbiB2YXJpYWJpbGl0eSBvZiBhZHVsdCBpbW1pZ3JhdGlvbiBhcyBTRCBvbiBuYXRydWFsIHNjYWxlDQoNCiMgRGVmaW5lIHRoZSBudW1iZXIgb2YgeWVhcnMgd2l0aCBwcmVkaWN0aW9ucyBhbmQgdGhlIE1vbnRlIENhcmxvIHNldHRpbmcNClQgPC0gMTAgICAgICAgICAgICAgICAgIyBOdW1iZXIgb2YgeWVhcnMgKHByb2plY3Rpb24gdGltZSBmcmFtZSkNCm5zaW0gPC0gMTAwMDAgICAgICAgICAgIyBOdW1iZXIgb2YgcmVwbGljYXRlIHBvcHVsYXRpb25zIHNpbXVsYXRlZA0KDQojIERlZmluZSBwb3B1bGF0aW9uIG1hdHJpeCBhbmQgaW5pdGlhbCBzdGFnZS1zcGVjaWZpYyBwb3B1bGF0aW9uIHNpemVzDQpOIDwtIGFycmF5KE5BLCBkaW09YygyLCBUKzEsIG5zaW0pKQ0KTlssMSxdIDwtIGMoMywxKQ0KciA8LSBtYXRyaXgoTkEsIG5yb3c9VCwgbmNvbD1uc2ltKQ0KYWxpdmUgPC0gbWF0cml4KE5BLCBucm93PVQsIG5jb2w9bnNpbSkNCm1lYW4uciA8LSBudW1lcmljKG5zaW0pDQoNCiMgUHJvamVjdCBwb3B1bGF0aW9uDQpmb3IgKHMgaW4gMTpuc2ltKXsgIyBMb29wIG92ZXIgcmVwbGljYXRlIHBvcHVsYXRpb25zDQogICNpZihzICUlIDEwMCA9PSAwKSB7Y2F0KHBhc3RlKCIqKiogU2ltcmVwIiwgcywgIioqKlxuIikpIH0gICAjIENvdW50ZXINCiAgIyBHZW5lcmF0ZSBhIG1lYW4gb2YgdGhlIGRlbW9ncmFwaGljIHJhdGVzIChzdWJqZWN0IHRvIG1lYXN1cmVtZW50IGVycm9yKQ0KICBtc2ogPC0gcmJldGEyKDEsIG1lYW4uc2osIHNkLnNqLmUpDQogIG1zYSA8LSByYmV0YTIoMSwgbWVhbi5zYSwgc2Quc2EuZSkNCiAgbWYxIDwtIHJub3JtKDEsIG1lYW4uZjEsIHNkLmYxLmUpDQogIG1mYSA8LSBybm9ybSgxLCBtZWFuLmZhLCBzZC5mYS5lKQ0KICBtaWEgPC0gcm5vcm0oMSwgbWVhbi5pbW0sIHNkLmltbS5lKQ0KDQogICMgR2VuZXJhdGUgYW5udWFsIGRlbW9ncmFwaGljIHJhdGVzIChzdWJqZWN0IHRvIHRlbXBvcmFsIHZhcmlhYmlsaXR5KQ0KICBzaiA8LSBwbG9naXMocm5vcm0oVCwgcWxvZ2lzKG1zaiksIHNkLnNqLnQpKQ0KICBzYSA8LSBwbG9naXMocm5vcm0oVCwgcWxvZ2lzKG1zYSksIHNkLnNhLnQpKQ0KICBmMSA8LSBwbWF4KDAsIHJub3JtKFQsIG1mMSwgc2QuZjEudCkpICAgICAgICAgICAgICAgICAgICAgICAjIEF2b2lkcyBuZWdhdGl2ZSB2YWx1ZXMNCiAgZmEgPC0gcG1heCgwLCBybm9ybShULCBtZmEsIHNkLmZhLnQpKSAgICAgICAgICAgICAgICAgICAgICAgIyBEaXR0bw0KICBpYSA8LSBwbWF4KDAsIHJub3JtKFQsIG1pYSwgc2QuaW1tLnQpKSAgICAgICAgICAgICAgICAgICAgICAgIyBEaXR0bw0KDQogICMgUHJvamVjdCBwb3B1bGF0aW9uIChpbmNsdWRlIGRlbW9ncmFwaGljIHN0b2NoYXN0aWNpdHkpDQogIGZvciAodCBpbiAxOlQpeyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgTG9vcCBvdmVyIHllYXJzDQogICAgTlsxLHQrMSxzXSA8LSBycG9pcygxLCBzalt0XSAqIChmMVt0XSAqIE5bMSx0LHNdICsgZmFbdF0gKiBOWzIsdCxzXSkpDQogICAgTlsyLHQrMSxzXSA8LSByYmlub20oMSwgc3VtKE5bLHQsc10pLCBzYVt0XSkrcnBvaXMoMSxpYSkNCiAgICBpZiAoc3VtKE5bLHQrMSxzXSkgPT0gMCkgYnJlYWsNCiAgICAjclt0LHNdIDwtIGxvZyhzdW0oTlssdCsxLHNdKSkgLSBsb2coc3VtKE5bLHQsc10pKQ0KICAgIGFsaXZlW3Qsc10gPC0gdA0KICB9ICN0DQogICNtZWFuLnJbc10gPC0gbWVhbihyW21pbihhbGl2ZVssc10sIG5hLnJtPVRSVUUpOm1heChhbGl2ZVssc10sIG5hLnJtPVRSVUUpLHNdKQ0KfSANCg0KI21lYW4obWVhbi5yKQ0KDQojc2QobWVhbi5yKQ0KDQoNCm5vdC5leHRpbmN0IDwtIHdoaWNoKCFpcy5uYShhbGl2ZVtULF0pKQ0KbWVhbihtZWFuLnJbbm90LmV4dGluY3RdKQ0KDQpzZChtZWFuLnJbbm90LmV4dGluY3RdKQ0KDQojIEV4dGluY3Rpb24gcHJvYmFiaWxpdHkgKGFmdGVyIFQgeWVhcnMpDQpzdW0oaXMubmEoYWxpdmVbVCxdKSkgLyBuc2ltDQoNCnJvd1N1bXMoaXMubmEoYWxpdmUpKSAvIG5zaW0NCg0KZGYgPC0gZGF0YS5mcmFtZSgNCiAgdG90YWxjb3VudD1jKGNvbFN1bXMoTlssLDE6bnNpbV0pKSwNCiAgdGltZT1yZXAoYygwOlQpLG5zaW0pLA0KICBzaW1udW1iZXI9Z2wobnNpbSwgVCsxKQ0KKQ0KDQoNCiMgcGxvdChqaXR0ZXIoYyhjb2xTdW1zKE5bLCwxOm5zaW1dKSksMSl+aml0dGVyKHJlcChjKDA6VCksbnNpbSksMSksIHBjaD0zKQ0KIyBib3hwbG90KGMoY29sU3VtcyhOWywsMTpuc2ltXSkpfmZhY3RvcihyZXAoYygwOlQpLG5zaW0pKSkNCiBieHBvYmo8LWJveHBsb3QoYyhjb2xTdW1zKE5bLCwxOm5zaW1dKSl+ZmFjdG9yKHJlcChjKDA6VCksbnNpbSkpLCBwbG90PUYpDQojIHBsb3Qoaml0dGVyKGMoY29sU3VtcyhOWywsMTpuc2ltXSkpLDEpfmppdHRlcihyZXAoYygwOlQpLG5zaW0pLDEpLCBwY2g9MykNCiMgcG9pbnRzKGJ4cG9iaiRzdGF0c1szLF1+YygwOlQpLCB0eXBlPSJsIiwgY29sPSJyZWQiLCBsd2Q9MikNCiMgDQojIHBhcihtYWk9YygxLDEsMC4xLDEpKQ0KIyBwbG90KGppdHRlcihjKGNvbFN1bXMoTlssLDE6bnNpbV0pKSwxKX5qaXR0ZXIocmVwKGMoMDpUKSxuc2ltKSwxKSwgcGNoPTMpDQojIHBvaW50cyhieHBvYmokc3RhdHNbMyxdfmMoMDpUKSwgdHlwZT0iYiIsIGNvbD0iYmx1ZSIsIGx3ZD0yLCBwY2g9MTYpDQojIHBhcihuZXc9VCkNCiMgcGxvdChjKHJvd1N1bXMoaXMubmEoYWxpdmUpKS9uc2ltKX5jKDE6VCksIHR5cGU9ImIiLCBjb2w9InJlZCIsIGJ0eT0ibiIsIHhsYWI9IiIsIHlsYWI9IiIsIGF4ZXM9RiwgeWxpbT1jKDAsMSksIHhsaW09YygwLFQpLCBsd2Q9MiwgcGNoPTE2KQ0KIyBheGlzKHNpZGU9NCwgYXQ9cHJldHR5KHJhbmdlKGMoMCwxKSkpKQ0KIyBtdGV4dCgicHJvYmFiaWxpdHkgb2YgZXh0aW5jdGlvbiIsIHNpZGU9NCwgbGluZT0zKQ0KDQpwYXIobWFpPWMoMSwxLDAuMSwxKSkNCnBsb3Qoaml0dGVyKGMoY29sU3VtcyhOWywsMTpuc2ltXSkpLDEpfmppdHRlcihyZXAoYygwOlQpLG5zaW0pLDEpLCBwY2g9MywgeGxhYj0ieWVhcnMgb2Ygc2ltdWxhdGlvbiIsIHlsYWI9ImVzdGltYXRlZCBwb3B1bGF0aW9uIHNpemUiKQ0KcG9pbnRzKGJ4cG9iaiRzdGF0c1szLF1+YygwOlQpLCB0eXBlPSJiIiwgY29sPSJibHVlIiwgbHdkPTIsIHBjaD0xNikNCnBhcihuZXc9VCkNCnBsb3QoYyhyb3dTdW1zKGlzLm5hKGFsaXZlKSkvbnNpbSl+YygxOlQpLCB0eXBlPSJiIiwgY29sPSJyZWQiLCBidHk9Im4iLCB4bGFiPSIiLCB5bGFiPSIiLCBheGVzPUYsIHlsaW09YygwLDEpLCB4bGltPWMoMCxUKSwgbHdkPTIsIHBjaD0xNikNCmF4aXMoc2lkZT00LCBhdD1wcmV0dHkocmFuZ2UoYygwLDEpKSkpDQptdGV4dCgicHJvcG9ydGlvbiBvZiBzaW11bGF0aW9ucyByZWFjaGVkIE49MCIsIHNpZGU9NCwgbGluZT0zLCBjb2w9InJlZCIpDQoNCg0KDQpnZ3Bsb3QoKSsNCiBnZW9tX2xpbmUoZGF0YT1kZiwgYWVzKHg9dGltZSwgeT10b3RhbGNvdW50LCBncm91cD1zaW1udW1iZXIpLCBsaW5ld2lkdGg9MSwgY29sb3I9ImdyYXkiLCBhbHBoYT0wLjgpICsNCiBnZW9tX2xpbmUoYWVzKHg9YygwOlQpLCB5PWJ4cG9iaiRzdGF0c1szLF0pLCBjb2xvcj0iYmx1ZSIsIGxpbmV3aWR0aD0zKSsNCiAjZ2VvbV9saW5lKGFlcyh4PWMoMTpUKSwgeT1jKHJvd1N1bXMoaXMubmEoYWxpdmUpKS9uc2ltKSksIGNvbD0icmVkIiwgbGluZXdpZHRoPTIpKw0KIGdlb21fbGFiZWwoYWVzKHg9YygxOlQpLCB5PTAsIGxhYmVsPXJvdW5kKGMocm93U3Vtcyhpcy5uYShhbGl2ZSkpL25zaW0pLCAyKSksIGNvbG9yPSJyZWQiKSsNCiBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMToxMCkpK3NjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsNTAsIGJ5PTIpKSsNCiB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZT0yMikgKw0KIGxhYnMoeD0iWWVhcnMgb2Ygc2ltdWxhdGVkIHBvcHVsYXRpb24gc2l6ZSBhbmRcbnByb3BvcnRpb24gb2Ygc2ltdWxhdGlvbnMgd2l0aCBOPTAiLCB5PSJUb3RhbCBzaW11bGF0ZWQgcG9wdWxhdGlvbiBjb3VudCIpDQoNCmdncGxvdCgpKw0KICBnZW9tX2ppdHRlcihkYXRhPWRmLCBhZXMoeD10aW1lLCB5PXRvdGFsY291bnQsIGdyb3VwPXNpbW51bWJlciksIHNoYXBlPSIuIiwgd2lkdGg9MC4zLCBoZWlnaHQ9MC4zKSArDQogIGdlb21fbGluZShhZXMoeD1jKDA6VCksIHk9Ynhwb2JqJHN0YXRzWzMsXSksIGNvbG9yPSJibHVlIiwgbGluZXdpZHRoPTMpKw0KICAjZ2VvbV9saW5lKGFlcyh4PWMoMTpUKSwgeT1jKHJvd1N1bXMoaXMubmEoYWxpdmUpKS9uc2ltKSksIGNvbD0icmVkIiwgbGluZXdpZHRoPTIpKw0KICBnZW9tX2xhYmVsKGFlcyh4PWMoMTpUKSwgeT0tMC41LCBsYWJlbD1yb3VuZChjKHJvd1N1bXMoaXMubmEoYWxpdmUpKS9uc2ltKSwgMikpLCBjb2xvcj0icmVkIikrDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygxOjEwKSkrc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCw1MCwgYnk9MikpKw0KICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZT0yMikrDQogIGxhYnMoeD0iWWVhcnMgb2Ygc2ltdWxhdGVkIHBvcHVsYXRpb24gc2l6ZSBhbmRcbnByb3BvcnRpb24gb2Ygc2ltdWxhdGlvbnMgd2l0aCBOPTAiLCB5PSJUb3RhbCBzaW11bGF0ZWQgcG9wdWxhdGlvbiBjb3VudCIpDQoNCiMgZ2dwbG90KCkrDQojICAgZ2VvbV9oZXgoZGF0YT1kZiwgYWVzKHg9dGltZSwgeT10b3RhbGNvdW50LCBncm91cD1zaW1udW1iZXIpLCBiaW5zPTEwKSArDQojICAgZ2VvbV9saW5lKGFlcyh4PWMoMDpUKSwgeT1ieHBvYmokc3RhdHNbMyxdKSwgY29sb3I9ImJsdWUiLCBsaW5ld2lkdGg9MykrDQojICAgI2dlb21fbGluZShhZXMoeD1jKDE6VCksIHk9Yyhyb3dTdW1zKGlzLm5hKGFsaXZlKSkvbnNpbSkpLCBjb2w9InJlZCIsIGxpbmV3aWR0aD0yKSsNCiMgICBnZW9tX2xhYmVsKGFlcyh4PWMoMTpUKSwgeT0tMC41LCBsYWJlbD1yb3VuZChjKHJvd1N1bXMoaXMubmEoYWxpdmUpKS9uc2ltKSwgMikpLCBjb2xvcj0icmVkIikrDQojICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDE6MTApKStzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLDUwLCBieT0yKSkrDQojICAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemU9MjIpKw0KIyAgIGxhYnMoeD0iWWVhcnMgb2Ygc2ltdWxhdGVkIHBvcHVsYXRpb24gc2l6ZSBhbmRcbnByb3BvcnRpb24gb2Ygc2ltdWxhdGlvbnMgd2l0aCBOPTAiLCB5PSJUb3RhbCBzaW11bGF0ZWQgcG9wdWxhdGlvbiBjb3VudCIpDQoNCg0KIyB+fn5+IFBsb3QgZ3JhcGggd2l0aCBwb3B1bGF0aW9uIGdyb3d0aCByYXRlcyAoRmlnLiAzLjE1KSAgfn5+fg0KIyBvcCA8LSBwYXIobWFyPWMoNCwgNCwgMiwgMSksIGxhcz0xLCBjZXg9MS4xLCAibWZyb3ciKQ0KIyBsYXlvdXQobWF0cml4KGMoMSwgMSwgMiwgMyksIDIsIDIsIGJ5cm93PVRSVUUpLCB3aWR0aHM9YygxLCAxKSwgaGVpZ2h0cz1jKDEsIDEpLCBUUlVFKQ0KIyBwbG90KHJbLDFdLCB0eXBlPSJsIiwgbHdkPTAuNSwgeWxhYj0iQW5udWFsIHBvcHVsYXRpb24gZ3Jvd3RoIHJhdGUiLCB4bGFiPSJUaW1lIiwNCiMgICAgIHlsaW09cmFuZ2Uoclt3aGljaCghaXMubmEoYWxpdmUpKV0pLCBjb2w9ImxpZ2h0Z3JleSIsIGF4ZXM9RkFMU0UpDQojIGF4aXMoMSk7IGF4aXMoMikNCiMgZm9yIChzIGluIDI6bnNpbSl7DQojICAgbGluZXMoclshaXMubmEoYWxpdmVbLHNdKSxzXSwgbHdkPTAuNSwgY29sPSJsaWdodGdyZXkiKQ0KIyB9DQojIGxpbmVzKGFwcGx5KHIsIDEsIG1lYW4sIG5hLnJtPVRSVUUpLCBsd2Q9MS41KQ0KIyBtdGV4dCgiQSIsIGF0PTAsIGNleD0xLjUpDQojIGEgPC0gaGlzdChtZWFuLnIsIG5jbGFzcz01MCwgY29sPSJkb2RnZXJibHVlIiwgbWFpbj0iIiwNCiMgICAgIHhsYWI9IlBvcHVsYXRpb24gZ3Jvd3RoIHJhdGUiLCBheGVzPUZBTFNFKSAjeGxpbT1jKC0yLjUsIDAuMSksIA0KIyBheGlzKDEpDQojIGF4aXMoMiwgYXQ9YygwLCA1MDAwLCAxMDAwMCwgMTUwMDAsIDIwMDAwLCAyNTAwMCwgMzAwMDApLCBsYWJlbHM9YygwLCA1LCAxMCwgMTUsIDIwLCAyNSwgMzApKQ0KIyBtdGV4dCgiQiIsIGF0PWEkbWlkc1sxXSwgY2V4PTEuNSkNCiMgYSA8LSBoaXN0KG1lYW4ucltub3QuZXh0aW5jdF0sIG5jbGFzcz0yNSwgY29sPSJkb2RnZXJibHVlIiwgbWFpbj0iIiwNCiMgICAgIHhsYWI9IlBvcHVsYXRpb24gZ3Jvd3RoIHJhdGUiLCBheGVzPUZBTFNFKQ0KIyBheGlzKDEpDQojIGF4aXMoMiwgYXQ9YygwLCAyMDAwLCA0MDAwLCA2MDAwLCA4MDAwLCAxMDAwMCksIGxhYmVscz1jKDAsIDIsIDQsIDYsIDgsIDEwKSkNCiMgbXRleHQoIkMiLCBhdD1hJG1pZHNbMV0sIGNleD0xLjUpDQojIHBhcihvcCkNCiMgfn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4NCg0KIyBodHRwczovL2dpdGh1Yi5jb20vbWlrZW1lcmVkaXRoL0lQTV9jb2RlL2Jsb2IvbWFpbi9JUE1fMDMvSVBNXzAzLjMuNS5SDQoNCg0KYGBgDQoNCg0KDQojIyMjIENvbnRyb2wgVHJlYXRtZW50IHNpbXVsYXRpb25zICANCg0KDQpgYGB7ciwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwfQ0KDQojIGh0dHBzOi8vZ2l0aHViLmNvbS9taWtlbWVyZWRpdGgvSVBNX2NvZGUvYmxvYi9tYWluL0lQTV8wMy9JUE1fMDMuMy41LlINCg0KIyAzLjMgQ2xhc3NpY2FsIGFuYWx5c2lzIG9mIGEgbWF0cml4IHBvcHVsYXRpb24gbW9kZWwNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCiMgMy4zLjUgQW5hbHlzaXMgb2YgYSBtYXRyaXggcG9wdWxhdGlvbiBtb2RlbCB3aXRoIGRpZmZlcmVudCBzb3VyY2VzIG9mDQojICAgICAgIHN0b2NoYXN0aWNpdHkgYW5kIHBhcmFtZXRlciB1bmNlcnRhaW50eQ0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyBEZWZpbmUgbWVhbiwgbWVhc3VyZW1lbnQgZXJyb3IgYW5kIHRlbXBvcmFsIHZhcmlhYmlsaXR5IG9mIHRoZSBkZW1vZ3JhcGhpYyBwYXJhbWV0ZXJzDQptZWFuLnNqIDwtIDAuMTE2MzYxNSAgICAgICAgICAjIE1lYW4gdmFsdWUgb2YganV2LiBzdXJ2aXZhbA0Kc2Quc2ouZSA8LSAwLjA1NTQ1ODggICAgICAgICMgVW5jZXJ0YWludHkgb2YgbWVhbiBqdXYuIHN1cnZpdmFsIGFzIFNEIG9uIG5hdHVyYWwgc2NhbGUNCnNkLnNqLnQgPC0gcGxvZ2lzKDAuMDMzMDQwMzgpICAgICAgICAgIyBwb3B1bGF0aW9uIHZhcmlhYmlsaXR5IG9mIGp1di4gc3Vydml2YWwgYXMgU0Qgb24gbG9naXQgc2NhbGUgIyBBbmRyZXcsIHRoaXMgbWlnaHQgaGF2ZSB0byBiZSBwbG9naXMoMC4wMzMwNDAzOCksIGJ1dCBub3Qgc3VyZSwgY2hlY2sgdGhlIHRleHQuDQptZWFuLnNhIDwtIDAuNTIyMiAgICAgICAgICMgTWVhbiB2YWx1ZSBvZiBhZC4gc3Vydml2YWwNCnNkLnNhLmUgPC0gMC4wNTc2OTY5MyAgICAgICAgIyBVbmNlcnRhaW50eSBvZiBtZWFuIGFkLiBzdXJ2aXZhbCBhcyBTRCBvbiBuYXR1cmFsIHNjYWxlDQpzZC5zYS50IDwtIHBsb2dpcygwLjAzODYyMjEpICAgICAgICAgIyBUZW1wb3JhbCB2YXJpYWJpbGl0eSBvZiBhZC4gc3Vydml2YWwgYXMgU0Qgb24gbG9naXQgc2NhbGUNCm1lYW4uZjEgPC0gMi41NzUgICAgICAgICAgIyBNZWFuIHZhbHVlIG9mIHByb2R1Y3Rpdml0eSBvZiAxeSBmZW1hbGVzDQpzZC5mMS5lIDwtIDAuMTMyNjAzMiAgICAgICAgICMgVW5jZXJ0YWludHkgb2YgbWVhbiBwcm9kdWN0aXZpdHkgYXMgU0Qgb24gbmF0dXJhbCBzY2FsZQ0Kc2QuZjEudCA8LSAwLjEwMTQ0NzkgICAgICAgICAgIyBUZW1wb3JhbCB2YXJpYWJpbGl0eSBvZiBwcm9kdWN0aXZpdHkgYXMgU0Qgb24gbmF0dXJhbCBzY2FsZQ0KbWVhbi5mYSA8LSAyLjU3NSAgICAgICAgICAjIE1lYW4gdmFsdWUgb2YgcHJvZHVjdGl2aXR5IG9mIGFkdWx0IGZlbWFsZXMNCnNkLmZhLmUgPC0gMC4xMzI2MDMyICAgICAgICAgIyBVbmNlcnRhaW50eSBvZiBtZWFuIHByb2R1Y3Rpdml0eSBhcyBTRCBvbiBuYXR1cmFsIHNjYWxlDQpzZC5mYS50IDwtIDAuMTAxICAgICAgICAgICMgVGVtcG9yYWwgdmFyaWFiaWxpdHkgb2YgcHJvZHVjdGl2aXR5IGFzIFNEIG9uIG5hdHVyYWwgc2NhbGUNCm1lYW4uaW1tIDwtIDAuMTkyNTg3ICAgICAgIyBNZWFuIHZhbHVlIG9mIGFkdWx0IGltbWlncmF0aW9uICANCnNkLmltbS5lIDwtIDAuMDY2NzQ4MDkgICAgIyBVbmNlcnRhaW50eSBvZiBtZWFuIGFkdWx0IGltbWlncmF0aW9uIGFzIFNEIG9uIG5hdHVyYWwgc2NhbGUNCnNkLmltbS50IDwtIDAuMDI4NzIyODEgICAgIyBwb3B1bGF0aW9uIHZhcmlhYmlsaXR5IG9mIGFkdWx0IGltbWlncmF0aW9uIGFzIFNEIG9uIG5hdHJ1YWwgc2NhbGUNCg0KIyBEZWZpbmUgdGhlIG51bWJlciBvZiB5ZWFycyB3aXRoIHByZWRpY3Rpb25zIGFuZCB0aGUgTW9udGUgQ2FybG8gc2V0dGluZw0KVCA8LSAxMCAgICAgICAgICAgICAgICAjIE51bWJlciBvZiB5ZWFycyAocHJvamVjdGlvbiB0aW1lIGZyYW1lKQ0KbnNpbSA8LSAxMDAwMCAgICAgICAgICAjIE51bWJlciBvZiByZXBsaWNhdGUgcG9wdWxhdGlvbnMgc2ltdWxhdGVkDQoNCiMgRGVmaW5lIHBvcHVsYXRpb24gbWF0cml4IGFuZCBpbml0aWFsIHN0YWdlLXNwZWNpZmljIHBvcHVsYXRpb24gc2l6ZXMNCk4gPC0gYXJyYXkoTkEsIGRpbT1jKDIsIFQrMSwgbnNpbSkpDQpOWywxLF0gPC0gYygzLDEpDQpyIDwtIG1hdHJpeChOQSwgbnJvdz1ULCBuY29sPW5zaW0pDQphbGl2ZSA8LSBtYXRyaXgoTkEsIG5yb3c9VCwgbmNvbD1uc2ltKQ0KbWVhbi5yIDwtIG51bWVyaWMobnNpbSkNCg0KIyBQcm9qZWN0IHBvcHVsYXRpb24NCmZvciAocyBpbiAxOm5zaW0peyAjIExvb3Agb3ZlciByZXBsaWNhdGUgcG9wdWxhdGlvbnMNCiAgI2lmKHMgJSUgMTAwID09IDApIHtjYXQocGFzdGUoIioqKiBTaW1yZXAiLCBzLCAiKioqXG4iKSkgfSAgICMgQ291bnRlcg0KICAjIEdlbmVyYXRlIGEgbWVhbiBvZiB0aGUgZGVtb2dyYXBoaWMgcmF0ZXMgKHN1YmplY3QgdG8gbWVhc3VyZW1lbnQgZXJyb3IpDQogIG1zaiA8LSByYmV0YTIoMSwgbWVhbi5zaiwgc2Quc2ouZSkNCiAgbXNhIDwtIHJiZXRhMigxLCBtZWFuLnNhLCBzZC5zYS5lKQ0KICBtZjEgPC0gcm5vcm0oMSwgbWVhbi5mMSwgc2QuZjEuZSkNCiAgbWZhIDwtIHJub3JtKDEsIG1lYW4uZmEsIHNkLmZhLmUpDQogIG1pYSA8LSBybm9ybSgxLCBtZWFuLmltbSwgc2QuaW1tLmUpDQoNCiAgIyBHZW5lcmF0ZSBhbm51YWwgZGVtb2dyYXBoaWMgcmF0ZXMgKHN1YmplY3QgdG8gdGVtcG9yYWwgdmFyaWFiaWxpdHkpDQogIHNqIDwtIHBsb2dpcyhybm9ybShULCBxbG9naXMobXNqKSwgc2Quc2oudCkpDQogIHNhIDwtIHBsb2dpcyhybm9ybShULCBxbG9naXMobXNhKSwgc2Quc2EudCkpDQogIGYxIDwtIHBtYXgoMCwgcm5vcm0oVCwgbWYxLCBzZC5mMS50KSkgICAgICAgICAgICAgICAgICAgICAgICMgQXZvaWRzIG5lZ2F0aXZlIHZhbHVlcw0KICBmYSA8LSBwbWF4KDAsIHJub3JtKFQsIG1mYSwgc2QuZmEudCkpICAgICAgICAgICAgICAgICAgICAgICAjIERpdHRvDQogIGlhIDwtIHBtYXgoMCwgcm5vcm0oVCwgbWlhLCBzZC5pbW0udCkpICAgICAgICAgICAgICAgICAgICAgICAjIERpdHRvDQoNCiAgIyBQcm9qZWN0IHBvcHVsYXRpb24gKGluY2x1ZGUgZGVtb2dyYXBoaWMgc3RvY2hhc3RpY2l0eSkNCiAgZm9yICh0IGluIDE6VCl7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBMb29wIG92ZXIgeWVhcnMNCiAgICBOWzEsdCsxLHNdIDwtIHJwb2lzKDEsIHNqW3RdICogKGYxW3RdICogTlsxLHQsc10gKyBmYVt0XSAqIE5bMix0LHNdKSkNCiAgICBOWzIsdCsxLHNdIDwtIHJiaW5vbSgxLCBzdW0oTlssdCxzXSksIHNhW3RdKStycG9pcygxLGlhKQ0KICAgIGlmIChzdW0oTlssdCsxLHNdKSA9PSAwKSBicmVhaw0KICAgICNyW3Qsc10gPC0gbG9nKHN1bShOWyx0KzEsc10pKSAtIGxvZyhzdW0oTlssdCxzXSkpDQogICAgYWxpdmVbdCxzXSA8LSB0DQogIH0gI3QNCiAgI21lYW4ucltzXSA8LSBtZWFuKHJbbWluKGFsaXZlWyxzXSwgbmEucm09VFJVRSk6bWF4KGFsaXZlWyxzXSwgbmEucm09VFJVRSksc10pDQp9IA0KDQojbWVhbihtZWFuLnIpDQoNCiNzZChtZWFuLnIpDQoNCg0Kbm90LmV4dGluY3QgPC0gd2hpY2goIWlzLm5hKGFsaXZlW1QsXSkpDQptZWFuKG1lYW4ucltub3QuZXh0aW5jdF0pDQoNCnNkKG1lYW4ucltub3QuZXh0aW5jdF0pDQoNCiMgRXh0aW5jdGlvbiBwcm9iYWJpbGl0eSAoYWZ0ZXIgVCB5ZWFycykNCnN1bShpcy5uYShhbGl2ZVtULF0pKSAvIG5zaW0NCg0Kcm93U3Vtcyhpcy5uYShhbGl2ZSkpIC8gbnNpbQ0KDQpkZiA8LSBkYXRhLmZyYW1lKA0KICB0b3RhbGNvdW50PWMoY29sU3VtcyhOWywsMTpuc2ltXSkpLA0KICB0aW1lPXJlcChjKDA6VCksbnNpbSksDQogIHNpbW51bWJlcj1nbChuc2ltLCBUKzEpDQopDQoNCg0KIyBwbG90KGppdHRlcihjKGNvbFN1bXMoTlssLDE6bnNpbV0pKSwxKX5qaXR0ZXIocmVwKGMoMDpUKSxuc2ltKSwxKSwgcGNoPTMpDQojIGJveHBsb3QoYyhjb2xTdW1zKE5bLCwxOm5zaW1dKSl+ZmFjdG9yKHJlcChjKDA6VCksbnNpbSkpKQ0KIGJ4cG9iajwtYm94cGxvdChjKGNvbFN1bXMoTlssLDE6bnNpbV0pKX5mYWN0b3IocmVwKGMoMDpUKSxuc2ltKSksIHBsb3Q9RikNCiMgcGxvdChqaXR0ZXIoYyhjb2xTdW1zKE5bLCwxOm5zaW1dKSksMSl+aml0dGVyKHJlcChjKDA6VCksbnNpbSksMSksIHBjaD0zKQ0KIyBwb2ludHMoYnhwb2JqJHN0YXRzWzMsXX5jKDA6VCksIHR5cGU9ImwiLCBjb2w9InJlZCIsIGx3ZD0yKQ0KIyANCiMgcGFyKG1haT1jKDEsMSwwLjEsMSkpDQojIHBsb3Qoaml0dGVyKGMoY29sU3VtcyhOWywsMTpuc2ltXSkpLDEpfmppdHRlcihyZXAoYygwOlQpLG5zaW0pLDEpLCBwY2g9MykNCiMgcG9pbnRzKGJ4cG9iaiRzdGF0c1szLF1+YygwOlQpLCB0eXBlPSJiIiwgY29sPSJibHVlIiwgbHdkPTIsIHBjaD0xNikNCiMgcGFyKG5ldz1UKQ0KIyBwbG90KGMocm93U3Vtcyhpcy5uYShhbGl2ZSkpL25zaW0pfmMoMTpUKSwgdHlwZT0iYiIsIGNvbD0icmVkIiwgYnR5PSJuIiwgeGxhYj0iIiwgeWxhYj0iIiwgYXhlcz1GLCB5bGltPWMoMCwxKSwgeGxpbT1jKDAsVCksIGx3ZD0yLCBwY2g9MTYpDQojIGF4aXMoc2lkZT00LCBhdD1wcmV0dHkocmFuZ2UoYygwLDEpKSkpDQojIG10ZXh0KCJwcm9iYWJpbGl0eSBvZiBleHRpbmN0aW9uIiwgc2lkZT00LCBsaW5lPTMpDQoNCnBhcihtYWk9YygxLDEsMC4xLDEpKQ0KcGxvdChqaXR0ZXIoYyhjb2xTdW1zKE5bLCwxOm5zaW1dKSksMSl+aml0dGVyKHJlcChjKDA6VCksbnNpbSksMSksIHBjaD0zLCB4bGFiPSJ5ZWFycyBvZiBzaW11bGF0aW9uIiwgeWxhYj0iZXN0aW1hdGVkIHBvcHVsYXRpb24gc2l6ZSIpDQpwb2ludHMoYnhwb2JqJHN0YXRzWzMsXX5jKDA6VCksIHR5cGU9ImIiLCBjb2w9ImJsdWUiLCBsd2Q9MiwgcGNoPTE2KQ0KcGFyKG5ldz1UKQ0KcGxvdChjKHJvd1N1bXMoaXMubmEoYWxpdmUpKS9uc2ltKX5jKDE6VCksIHR5cGU9ImIiLCBjb2w9InJlZCIsIGJ0eT0ibiIsIHhsYWI9IiIsIHlsYWI9IiIsIGF4ZXM9RiwgeWxpbT1jKDAsMSksIHhsaW09YygwLFQpLCBsd2Q9MiwgcGNoPTE2KQ0KYXhpcyhzaWRlPTQsIGF0PXByZXR0eShyYW5nZShjKDAsMSkpKSkNCm10ZXh0KCJwcm9wb3J0aW9uIG9mIHNpbXVsYXRpb25zIHJlYWNoZWQgTj0wIiwgc2lkZT00LCBsaW5lPTMsIGNvbD0icmVkIikNCg0KDQoNCmdncGxvdCgpKw0KIGdlb21fbGluZShkYXRhPWRmLCBhZXMoeD10aW1lLCB5PXRvdGFsY291bnQsIGdyb3VwPXNpbW51bWJlciksIGxpbmV3aWR0aD0xLCBjb2xvcj0iZ3JheSIsIGFscGhhPTAuOCkgKw0KIGdlb21fbGluZShhZXMoeD1jKDA6VCksIHk9Ynhwb2JqJHN0YXRzWzMsXSksIGNvbG9yPSJibHVlIiwgbGluZXdpZHRoPTMpKw0KICNnZW9tX2xpbmUoYWVzKHg9YygxOlQpLCB5PWMocm93U3Vtcyhpcy5uYShhbGl2ZSkpL25zaW0pKSwgY29sPSJyZWQiLCBsaW5ld2lkdGg9MikrDQogZ2VvbV9sYWJlbChhZXMoeD1jKDE6VCksIHk9MCwgbGFiZWw9cm91bmQoYyhyb3dTdW1zKGlzLm5hKGFsaXZlKSkvbnNpbSksIDIpKSwgY29sb3I9InJlZCIpKw0KIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygxOjEwKSkrc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCw1MCwgYnk9MikpKw0KIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplPTIyKSArDQogbGFicyh4PSJZZWFycyBvZiBzaW11bGF0ZWQgcG9wdWxhdGlvbiBzaXplIGFuZFxucHJvcG9ydGlvbiBvZiBzaW11bGF0aW9ucyB3aXRoIE49MCIsIHk9IlRvdGFsIHNpbXVsYXRlZCBwb3B1bGF0aW9uIGNvdW50IikNCg0KZ2dwbG90KCkrDQogIGdlb21faml0dGVyKGRhdGE9ZGYsIGFlcyh4PXRpbWUsIHk9dG90YWxjb3VudCwgZ3JvdXA9c2ltbnVtYmVyKSwgc2hhcGU9Ii4iLCB3aWR0aD0wLjMsIGhlaWdodD0wLjMpICsNCiAgZ2VvbV9saW5lKGFlcyh4PWMoMDpUKSwgeT1ieHBvYmokc3RhdHNbMyxdKSwgY29sb3I9ImJsdWUiLCBsaW5ld2lkdGg9MykrDQogICNnZW9tX2xpbmUoYWVzKHg9YygxOlQpLCB5PWMocm93U3Vtcyhpcy5uYShhbGl2ZSkpL25zaW0pKSwgY29sPSJyZWQiLCBsaW5ld2lkdGg9MikrDQogIGdlb21fbGFiZWwoYWVzKHg9YygxOlQpLCB5PS0wLjUsIGxhYmVsPXJvdW5kKGMocm93U3Vtcyhpcy5uYShhbGl2ZSkpL25zaW0pLCAyKSksIGNvbG9yPSJyZWQiKSsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDE6MTApKStzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLDUwLCBieT0yKSkrDQogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplPTIyKSsNCiAgbGFicyh4PSJZZWFycyBvZiBzaW11bGF0ZWQgcG9wdWxhdGlvbiBzaXplIGFuZFxucHJvcG9ydGlvbiBvZiBzaW11bGF0aW9ucyB3aXRoIE49MCIsIHk9IlRvdGFsIHNpbXVsYXRlZCBwb3B1bGF0aW9uIGNvdW50IikNCg0KIyBnZ3Bsb3QoKSsNCiMgICBnZW9tX2hleChkYXRhPWRmLCBhZXMoeD10aW1lLCB5PXRvdGFsY291bnQsIGdyb3VwPXNpbW51bWJlciksIGJpbnM9MTApICsNCiMgICBnZW9tX2xpbmUoYWVzKHg9YygwOlQpLCB5PWJ4cG9iaiRzdGF0c1szLF0pLCBjb2xvcj0iYmx1ZSIsIGxpbmV3aWR0aD0zKSsNCiMgICAjZ2VvbV9saW5lKGFlcyh4PWMoMTpUKSwgeT1jKHJvd1N1bXMoaXMubmEoYWxpdmUpKS9uc2ltKSksIGNvbD0icmVkIiwgbGluZXdpZHRoPTIpKw0KIyAgIGdlb21fbGFiZWwoYWVzKHg9YygxOlQpLCB5PS0wLjUsIGxhYmVsPXJvdW5kKGMocm93U3Vtcyhpcy5uYShhbGl2ZSkpL25zaW0pLCAyKSksIGNvbG9yPSJyZWQiKSsNCiMgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMToxMCkpK3NjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsNTAsIGJ5PTIpKSsNCiMgICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZT0yMikrDQojICAgbGFicyh4PSJZZWFycyBvZiBzaW11bGF0ZWQgcG9wdWxhdGlvbiBzaXplIGFuZFxucHJvcG9ydGlvbiBvZiBzaW11bGF0aW9ucyB3aXRoIE49MCIsIHk9IlRvdGFsIHNpbXVsYXRlZCBwb3B1bGF0aW9uIGNvdW50IikNCg0KDQojIH5+fn4gUGxvdCBncmFwaCB3aXRoIHBvcHVsYXRpb24gZ3Jvd3RoIHJhdGVzIChGaWcuIDMuMTUpICB+fn5+DQojIG9wIDwtIHBhcihtYXI9Yyg0LCA0LCAyLCAxKSwgbGFzPTEsIGNleD0xLjEsICJtZnJvdyIpDQojIGxheW91dChtYXRyaXgoYygxLCAxLCAyLCAzKSwgMiwgMiwgYnlyb3c9VFJVRSksIHdpZHRocz1jKDEsIDEpLCBoZWlnaHRzPWMoMSwgMSksIFRSVUUpDQojIHBsb3QoclssMV0sIHR5cGU9ImwiLCBsd2Q9MC41LCB5bGFiPSJBbm51YWwgcG9wdWxhdGlvbiBncm93dGggcmF0ZSIsIHhsYWI9IlRpbWUiLA0KIyAgICAgeWxpbT1yYW5nZShyW3doaWNoKCFpcy5uYShhbGl2ZSkpXSksIGNvbD0ibGlnaHRncmV5IiwgYXhlcz1GQUxTRSkNCiMgYXhpcygxKTsgYXhpcygyKQ0KIyBmb3IgKHMgaW4gMjpuc2ltKXsNCiMgICBsaW5lcyhyWyFpcy5uYShhbGl2ZVssc10pLHNdLCBsd2Q9MC41LCBjb2w9ImxpZ2h0Z3JleSIpDQojIH0NCiMgbGluZXMoYXBwbHkociwgMSwgbWVhbiwgbmEucm09VFJVRSksIGx3ZD0xLjUpDQojIG10ZXh0KCJBIiwgYXQ9MCwgY2V4PTEuNSkNCiMgYSA8LSBoaXN0KG1lYW4uciwgbmNsYXNzPTUwLCBjb2w9ImRvZGdlcmJsdWUiLCBtYWluPSIiLA0KIyAgICAgeGxhYj0iUG9wdWxhdGlvbiBncm93dGggcmF0ZSIsIGF4ZXM9RkFMU0UpICN4bGltPWMoLTIuNSwgMC4xKSwgDQojIGF4aXMoMSkNCiMgYXhpcygyLCBhdD1jKDAsIDUwMDAsIDEwMDAwLCAxNTAwMCwgMjAwMDAsIDI1MDAwLCAzMDAwMCksIGxhYmVscz1jKDAsIDUsIDEwLCAxNSwgMjAsIDI1LCAzMCkpDQojIG10ZXh0KCJCIiwgYXQ9YSRtaWRzWzFdLCBjZXg9MS41KQ0KIyBhIDwtIGhpc3QobWVhbi5yW25vdC5leHRpbmN0XSwgbmNsYXNzPTI1LCBjb2w9ImRvZGdlcmJsdWUiLCBtYWluPSIiLA0KIyAgICAgeGxhYj0iUG9wdWxhdGlvbiBncm93dGggcmF0ZSIsIGF4ZXM9RkFMU0UpDQojIGF4aXMoMSkNCiMgYXhpcygyLCBhdD1jKDAsIDIwMDAsIDQwMDAsIDYwMDAsIDgwMDAsIDEwMDAwKSwgbGFiZWxzPWMoMCwgMiwgNCwgNiwgOCwgMTApKQ0KIyBtdGV4dCgiQyIsIGF0PWEkbWlkc1sxXSwgY2V4PTEuNSkNCiMgcGFyKG9wKQ0KIyB+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fg0KDQojIGh0dHBzOi8vZ2l0aHViLmNvbS9taWtlbWVyZWRpdGgvSVBNX2NvZGUvYmxvYi9tYWluL0lQTV8wMy9JUE1fMDMuMy41LlINCg0KDQpgYGANCg0KDQoNCg0KIyMjIyBMb3cgVHJlYXRtZW50IHNpbXVsYXRpb25zICANCg0KDQpgYGB7ciwgZmlnLmhlaWdodD0xMCwgZmlnLndpZHRoPTEwfQ0KDQojIGh0dHBzOi8vZ2l0aHViLmNvbS9taWtlbWVyZWRpdGgvSVBNX2NvZGUvYmxvYi9tYWluL0lQTV8wMy9JUE1fMDMuMy41LlINCg0KIyAzLjMgQ2xhc3NpY2FsIGFuYWx5c2lzIG9mIGEgbWF0cml4IHBvcHVsYXRpb24gbW9kZWwNCiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09DQoNCiMgMy4zLjUgQW5hbHlzaXMgb2YgYSBtYXRyaXggcG9wdWxhdGlvbiBtb2RlbCB3aXRoIGRpZmZlcmVudCBzb3VyY2VzIG9mDQojICAgICAgIHN0b2NoYXN0aWNpdHkgYW5kIHBhcmFtZXRlciB1bmNlcnRhaW50eQ0KIyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0NCg0KIyBEZWZpbmUgbWVhbiwgbWVhc3VyZW1lbnQgZXJyb3IgYW5kIHRlbXBvcmFsIHZhcmlhYmlsaXR5IG9mIHRoZSBkZW1vZ3JhcGhpYyBwYXJhbWV0ZXJzDQptZWFuLnNqIDwtIDAuMTE2MzYxNSAgICAgICAgICAjIE1lYW4gdmFsdWUgb2YganV2LiBzdXJ2aXZhbA0Kc2Quc2ouZSA8LSAwLjA1NTQ1ODggICAgICAgICMgVW5jZXJ0YWludHkgb2YgbWVhbiBqdXYuIHN1cnZpdmFsIGFzIFNEIG9uIG5hdHVyYWwgc2NhbGUNCnNkLnNqLnQgPC0gcGxvZ2lzKDAuMDMzMDQwMzgpICAgICAgICAgIyBwb3B1bGF0aW9uIHZhcmlhYmlsaXR5IG9mIGp1di4gc3Vydml2YWwgYXMgU0Qgb24gbG9naXQgc2NhbGUgIyBBbmRyZXcsIHRoaXMgbWlnaHQgaGF2ZSB0byBiZSBwbG9naXMoMC4wMzMwNDAzOCksIGJ1dCBub3Qgc3VyZSwgY2hlY2sgdGhlIHRleHQuDQptZWFuLnNhIDwtIDAuNTIyMiAgICAgICAgICMgTWVhbiB2YWx1ZSBvZiBhZC4gc3Vydml2YWwNCnNkLnNhLmUgPC0gMC4wNTc2OTY5MyAgICAgICAgIyBVbmNlcnRhaW50eSBvZiBtZWFuIGFkLiBzdXJ2aXZhbCBhcyBTRCBvbiBuYXR1cmFsIHNjYWxlDQpzZC5zYS50IDwtIHBsb2dpcygwLjAzODYyMjEpICAgICAgICAgIyBUZW1wb3JhbCB2YXJpYWJpbGl0eSBvZiBhZC4gc3Vydml2YWwgYXMgU0Qgb24gbG9naXQgc2NhbGUNCm1lYW4uZjEgPC0gMi4yNjQgICAgICAgICAgIyBNZWFuIHZhbHVlIG9mIHByb2R1Y3Rpdml0eSBvZiAxeSBmZW1hbGVzDQpzZC5mMS5lIDwtIDAuMTMyNjAzMiAgICAgICAgICMgVW5jZXJ0YWludHkgb2YgbWVhbiBwcm9kdWN0aXZpdHkgYXMgU0Qgb24gbmF0dXJhbCBzY2FsZQ0Kc2QuZjEudCA8LSAwLjEwMTQ0NzkgICAgICAgICAgIyBUZW1wb3JhbCB2YXJpYWJpbGl0eSBvZiBwcm9kdWN0aXZpdHkgYXMgU0Qgb24gbmF0dXJhbCBzY2FsZQ0KbWVhbi5mYSA8LSAyLjI2NCAgICAgICAgICAjIE1lYW4gdmFsdWUgb2YgcHJvZHVjdGl2aXR5IG9mIGFkdWx0IGZlbWFsZXMNCnNkLmZhLmUgPC0gMC4xMzI2MDMyICAgICAgICAgIyBVbmNlcnRhaW50eSBvZiBtZWFuIHByb2R1Y3Rpdml0eSBhcyBTRCBvbiBuYXR1cmFsIHNjYWxlDQpzZC5mYS50IDwtIDAuMTAxICAgICAgICAgICMgVGVtcG9yYWwgdmFyaWFiaWxpdHkgb2YgcHJvZHVjdGl2aXR5IGFzIFNEIG9uIG5hdHVyYWwgc2NhbGUNCm1lYW4uaW1tIDwtIDAuMTkyNTg3ICAgICAgIyBNZWFuIHZhbHVlIG9mIGFkdWx0IGltbWlncmF0aW9uICANCnNkLmltbS5lIDwtIDAuMDY2NzQ4MDkgICAgIyBVbmNlcnRhaW50eSBvZiBtZWFuIGFkdWx0IGltbWlncmF0aW9uIGFzIFNEIG9uIG5hdHVyYWwgc2NhbGUNCnNkLmltbS50IDwtIDAuMDI4NzIyODEgICAgIyBwb3B1bGF0aW9uIHZhcmlhYmlsaXR5IG9mIGFkdWx0IGltbWlncmF0aW9uIGFzIFNEIG9uIG5hdHJ1YWwgc2NhbGUNCg0KIyBEZWZpbmUgdGhlIG51bWJlciBvZiB5ZWFycyB3aXRoIHByZWRpY3Rpb25zIGFuZCB0aGUgTW9udGUgQ2FybG8gc2V0dGluZw0KVCA8LSAxMCAgICAgICAgICAgICAgICAjIE51bWJlciBvZiB5ZWFycyAocHJvamVjdGlvbiB0aW1lIGZyYW1lKQ0KbnNpbSA8LSAxMDAwMCAgICAgICAgICAjIE51bWJlciBvZiByZXBsaWNhdGUgcG9wdWxhdGlvbnMgc2ltdWxhdGVkDQoNCiMgRGVmaW5lIHBvcHVsYXRpb24gbWF0cml4IGFuZCBpbml0aWFsIHN0YWdlLXNwZWNpZmljIHBvcHVsYXRpb24gc2l6ZXMNCk4gPC0gYXJyYXkoTkEsIGRpbT1jKDIsIFQrMSwgbnNpbSkpDQpOWywxLF0gPC0gYygzLDEpDQpyIDwtIG1hdHJpeChOQSwgbnJvdz1ULCBuY29sPW5zaW0pDQphbGl2ZSA8LSBtYXRyaXgoTkEsIG5yb3c9VCwgbmNvbD1uc2ltKQ0KbWVhbi5yIDwtIG51bWVyaWMobnNpbSkNCg0KIyBQcm9qZWN0IHBvcHVsYXRpb24NCmZvciAocyBpbiAxOm5zaW0peyAjIExvb3Agb3ZlciByZXBsaWNhdGUgcG9wdWxhdGlvbnMNCiAgI2lmKHMgJSUgMTAwID09IDApIHtjYXQocGFzdGUoIioqKiBTaW1yZXAiLCBzLCAiKioqXG4iKSkgfSAgICMgQ291bnRlcg0KICAjIEdlbmVyYXRlIGEgbWVhbiBvZiB0aGUgZGVtb2dyYXBoaWMgcmF0ZXMgKHN1YmplY3QgdG8gbWVhc3VyZW1lbnQgZXJyb3IpDQogIG1zaiA8LSByYmV0YTIoMSwgbWVhbi5zaiwgc2Quc2ouZSkNCiAgbXNhIDwtIHJiZXRhMigxLCBtZWFuLnNhLCBzZC5zYS5lKQ0KICBtZjEgPC0gcm5vcm0oMSwgbWVhbi5mMSwgc2QuZjEuZSkNCiAgbWZhIDwtIHJub3JtKDEsIG1lYW4uZmEsIHNkLmZhLmUpDQogIG1pYSA8LSBybm9ybSgxLCBtZWFuLmltbSwgc2QuaW1tLmUpDQoNCiAgIyBHZW5lcmF0ZSBhbm51YWwgZGVtb2dyYXBoaWMgcmF0ZXMgKHN1YmplY3QgdG8gdGVtcG9yYWwgdmFyaWFiaWxpdHkpDQogIHNqIDwtIHBsb2dpcyhybm9ybShULCBxbG9naXMobXNqKSwgc2Quc2oudCkpDQogIHNhIDwtIHBsb2dpcyhybm9ybShULCBxbG9naXMobXNhKSwgc2Quc2EudCkpDQogIGYxIDwtIHBtYXgoMCwgcm5vcm0oVCwgbWYxLCBzZC5mMS50KSkgICAgICAgICAgICAgICAgICAgICAgICMgQXZvaWRzIG5lZ2F0aXZlIHZhbHVlcw0KICBmYSA8LSBwbWF4KDAsIHJub3JtKFQsIG1mYSwgc2QuZmEudCkpICAgICAgICAgICAgICAgICAgICAgICAjIERpdHRvDQogIGlhIDwtIHBtYXgoMCwgcm5vcm0oVCwgbWlhLCBzZC5pbW0udCkpICAgICAgICAgICAgICAgICAgICAgICAjIERpdHRvDQoNCiAgIyBQcm9qZWN0IHBvcHVsYXRpb24gKGluY2x1ZGUgZGVtb2dyYXBoaWMgc3RvY2hhc3RpY2l0eSkNCiAgZm9yICh0IGluIDE6VCl7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIyBMb29wIG92ZXIgeWVhcnMNCiAgICBOWzEsdCsxLHNdIDwtIHJwb2lzKDEsIHNqW3RdICogKGYxW3RdICogTlsxLHQsc10gKyBmYVt0XSAqIE5bMix0LHNdKSkNCiAgICBOWzIsdCsxLHNdIDwtIHJiaW5vbSgxLCBzdW0oTlssdCxzXSksIHNhW3RdKStycG9pcygxLGlhKQ0KICAgIGlmIChzdW0oTlssdCsxLHNdKSA9PSAwKSBicmVhaw0KICAgICNyW3Qsc10gPC0gbG9nKHN1bShOWyx0KzEsc10pKSAtIGxvZyhzdW0oTlssdCxzXSkpDQogICAgYWxpdmVbdCxzXSA8LSB0DQogIH0gI3QNCiAgI21lYW4ucltzXSA8LSBtZWFuKHJbbWluKGFsaXZlWyxzXSwgbmEucm09VFJVRSk6bWF4KGFsaXZlWyxzXSwgbmEucm09VFJVRSksc10pDQp9IA0KDQojbWVhbihtZWFuLnIpDQoNCiNzZChtZWFuLnIpDQoNCg0Kbm90LmV4dGluY3QgPC0gd2hpY2goIWlzLm5hKGFsaXZlW1QsXSkpDQptZWFuKG1lYW4ucltub3QuZXh0aW5jdF0pDQoNCnNkKG1lYW4ucltub3QuZXh0aW5jdF0pDQoNCiMgRXh0aW5jdGlvbiBwcm9iYWJpbGl0eSAoYWZ0ZXIgVCB5ZWFycykNCnN1bShpcy5uYShhbGl2ZVtULF0pKSAvIG5zaW0NCg0Kcm93U3Vtcyhpcy5uYShhbGl2ZSkpIC8gbnNpbQ0KDQpkZiA8LSBkYXRhLmZyYW1lKA0KICB0b3RhbGNvdW50PWMoY29sU3VtcyhOWywsMTpuc2ltXSkpLA0KICB0aW1lPXJlcChjKDA6VCksbnNpbSksDQogIHNpbW51bWJlcj1nbChuc2ltLCBUKzEpDQopDQoNCg0KIyBwbG90KGppdHRlcihjKGNvbFN1bXMoTlssLDE6bnNpbV0pKSwxKX5qaXR0ZXIocmVwKGMoMDpUKSxuc2ltKSwxKSwgcGNoPTMpDQojIGJveHBsb3QoYyhjb2xTdW1zKE5bLCwxOm5zaW1dKSl+ZmFjdG9yKHJlcChjKDA6VCksbnNpbSkpKQ0KIGJ4cG9iajwtYm94cGxvdChjKGNvbFN1bXMoTlssLDE6bnNpbV0pKX5mYWN0b3IocmVwKGMoMDpUKSxuc2ltKSksIHBsb3Q9RikNCiMgcGxvdChqaXR0ZXIoYyhjb2xTdW1zKE5bLCwxOm5zaW1dKSksMSl+aml0dGVyKHJlcChjKDA6VCksbnNpbSksMSksIHBjaD0zKQ0KIyBwb2ludHMoYnhwb2JqJHN0YXRzWzMsXX5jKDA6VCksIHR5cGU9ImwiLCBjb2w9InJlZCIsIGx3ZD0yKQ0KIyANCiMgcGFyKG1haT1jKDEsMSwwLjEsMSkpDQojIHBsb3Qoaml0dGVyKGMoY29sU3VtcyhOWywsMTpuc2ltXSkpLDEpfmppdHRlcihyZXAoYygwOlQpLG5zaW0pLDEpLCBwY2g9MykNCiMgcG9pbnRzKGJ4cG9iaiRzdGF0c1szLF1+YygwOlQpLCB0eXBlPSJiIiwgY29sPSJibHVlIiwgbHdkPTIsIHBjaD0xNikNCiMgcGFyKG5ldz1UKQ0KIyBwbG90KGMocm93U3Vtcyhpcy5uYShhbGl2ZSkpL25zaW0pfmMoMTpUKSwgdHlwZT0iYiIsIGNvbD0icmVkIiwgYnR5PSJuIiwgeGxhYj0iIiwgeWxhYj0iIiwgYXhlcz1GLCB5bGltPWMoMCwxKSwgeGxpbT1jKDAsVCksIGx3ZD0yLCBwY2g9MTYpDQojIGF4aXMoc2lkZT00LCBhdD1wcmV0dHkocmFuZ2UoYygwLDEpKSkpDQojIG10ZXh0KCJwcm9iYWJpbGl0eSBvZiBleHRpbmN0aW9uIiwgc2lkZT00LCBsaW5lPTMpDQoNCnBhcihtYWk9YygxLDEsMC4xLDEpKQ0KcGxvdChqaXR0ZXIoYyhjb2xTdW1zKE5bLCwxOm5zaW1dKSksMSl+aml0dGVyKHJlcChjKDA6VCksbnNpbSksMSksIHBjaD0zLCB4bGFiPSJ5ZWFycyBvZiBzaW11bGF0aW9uIiwgeWxhYj0iZXN0aW1hdGVkIHBvcHVsYXRpb24gc2l6ZSIpDQpwb2ludHMoYnhwb2JqJHN0YXRzWzMsXX5jKDA6VCksIHR5cGU9ImIiLCBjb2w9ImJsdWUiLCBsd2Q9MiwgcGNoPTE2KQ0KcGFyKG5ldz1UKQ0KcGxvdChjKHJvd1N1bXMoaXMubmEoYWxpdmUpKS9uc2ltKX5jKDE6VCksIHR5cGU9ImIiLCBjb2w9InJlZCIsIGJ0eT0ibiIsIHhsYWI9IiIsIHlsYWI9IiIsIGF4ZXM9RiwgeWxpbT1jKDAsMSksIHhsaW09YygwLFQpLCBsd2Q9MiwgcGNoPTE2KQ0KYXhpcyhzaWRlPTQsIGF0PXByZXR0eShyYW5nZShjKDAsMSkpKSkNCm10ZXh0KCJwcm9wb3J0aW9uIG9mIHNpbXVsYXRpb25zIHJlYWNoZWQgTj0wIiwgc2lkZT00LCBsaW5lPTMsIGNvbD0icmVkIikNCg0KDQoNCmdncGxvdCgpKw0KIGdlb21fbGluZShkYXRhPWRmLCBhZXMoeD10aW1lLCB5PXRvdGFsY291bnQsIGdyb3VwPXNpbW51bWJlciksIGxpbmV3aWR0aD0xLCBjb2xvcj0iZ3JheSIsIGFscGhhPTAuOCkgKw0KIGdlb21fbGluZShhZXMoeD1jKDA6VCksIHk9Ynhwb2JqJHN0YXRzWzMsXSksIGNvbG9yPSJibHVlIiwgbGluZXdpZHRoPTMpKw0KICNnZW9tX2xpbmUoYWVzKHg9YygxOlQpLCB5PWMocm93U3Vtcyhpcy5uYShhbGl2ZSkpL25zaW0pKSwgY29sPSJyZWQiLCBsaW5ld2lkdGg9MikrDQogZ2VvbV9sYWJlbChhZXMoeD1jKDE6VCksIHk9MCwgbGFiZWw9cm91bmQoYyhyb3dTdW1zKGlzLm5hKGFsaXZlKSkvbnNpbSksIDIpKSwgY29sb3I9InJlZCIpKw0KIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygxOjEwKSkrc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCw1MCwgYnk9MikpKw0KIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplPTIyKSArDQogbGFicyh4PSJZZWFycyBvZiBzaW11bGF0ZWQgcG9wdWxhdGlvbiBzaXplIGFuZFxucHJvcG9ydGlvbiBvZiBzaW11bGF0aW9ucyB3aXRoIE49MCIsIHk9IlRvdGFsIHNpbXVsYXRlZCBwb3B1bGF0aW9uIGNvdW50IikNCg0KZ2dwbG90KCkrDQogIGdlb21faml0dGVyKGRhdGE9ZGYsIGFlcyh4PXRpbWUsIHk9dG90YWxjb3VudCwgZ3JvdXA9c2ltbnVtYmVyKSwgc2hhcGU9Ii4iLCB3aWR0aD0wLjMsIGhlaWdodD0wLjMpICsNCiAgZ2VvbV9saW5lKGFlcyh4PWMoMDpUKSwgeT1ieHBvYmokc3RhdHNbMyxdKSwgY29sb3I9ImJsdWUiLCBsaW5ld2lkdGg9MykrDQogICNnZW9tX2xpbmUoYWVzKHg9YygxOlQpLCB5PWMocm93U3Vtcyhpcy5uYShhbGl2ZSkpL25zaW0pKSwgY29sPSJyZWQiLCBsaW5ld2lkdGg9MikrDQogIGdlb21fbGFiZWwoYWVzKHg9YygxOlQpLCB5PS0wLjUsIGxhYmVsPXJvdW5kKGMocm93U3Vtcyhpcy5uYShhbGl2ZSkpL25zaW0pLCAyKSksIGNvbG9yPSJyZWQiKSsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDE6MTApKStzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLDUwLCBieT0yKSkrDQogIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplPTIyKSsNCiAgbGFicyh4PSJZZWFycyBvZiBzaW11bGF0ZWQgcG9wdWxhdGlvbiBzaXplIGFuZFxucHJvcG9ydGlvbiBvZiBzaW11bGF0aW9ucyB3aXRoIE49MCIsIHk9IlRvdGFsIHNpbXVsYXRlZCBwb3B1bGF0aW9uIGNvdW50IikNCg0KIyBnZ3Bsb3QoKSsNCiMgICBnZW9tX2hleChkYXRhPWRmLCBhZXMoeD10aW1lLCB5PXRvdGFsY291bnQsIGdyb3VwPXNpbW51bWJlciksIGJpbnM9MTApICsNCiMgICBnZW9tX2xpbmUoYWVzKHg9YygwOlQpLCB5PWJ4cG9iaiRzdGF0c1szLF0pLCBjb2xvcj0iYmx1ZSIsIGxpbmV3aWR0aD0zKSsNCiMgICAjZ2VvbV9saW5lKGFlcyh4PWMoMTpUKSwgeT1jKHJvd1N1bXMoaXMubmEoYWxpdmUpKS9uc2ltKSksIGNvbD0icmVkIiwgbGluZXdpZHRoPTIpKw0KIyAgIGdlb21fbGFiZWwoYWVzKHg9YygxOlQpLCB5PS0wLjUsIGxhYmVsPXJvdW5kKGMocm93U3Vtcyhpcy5uYShhbGl2ZSkpL25zaW0pLCAyKSksIGNvbG9yPSJyZWQiKSsNCiMgICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMToxMCkpK3NjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsNTAsIGJ5PTIpKSsNCiMgICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZT0yMikrDQojICAgbGFicyh4PSJZZWFycyBvZiBzaW11bGF0ZWQgcG9wdWxhdGlvbiBzaXplIGFuZFxucHJvcG9ydGlvbiBvZiBzaW11bGF0aW9ucyB3aXRoIE49MCIsIHk9IlRvdGFsIHNpbXVsYXRlZCBwb3B1bGF0aW9uIGNvdW50IikNCg0KDQojIH5+fn4gUGxvdCBncmFwaCB3aXRoIHBvcHVsYXRpb24gZ3Jvd3RoIHJhdGVzIChGaWcuIDMuMTUpICB+fn5+DQojIG9wIDwtIHBhcihtYXI9Yyg0LCA0LCAyLCAxKSwgbGFzPTEsIGNleD0xLjEsICJtZnJvdyIpDQojIGxheW91dChtYXRyaXgoYygxLCAxLCAyLCAzKSwgMiwgMiwgYnlyb3c9VFJVRSksIHdpZHRocz1jKDEsIDEpLCBoZWlnaHRzPWMoMSwgMSksIFRSVUUpDQojIHBsb3QoclssMV0sIHR5cGU9ImwiLCBsd2Q9MC41LCB5bGFiPSJBbm51YWwgcG9wdWxhdGlvbiBncm93dGggcmF0ZSIsIHhsYWI9IlRpbWUiLA0KIyAgICAgeWxpbT1yYW5nZShyW3doaWNoKCFpcy5uYShhbGl2ZSkpXSksIGNvbD0ibGlnaHRncmV5IiwgYXhlcz1GQUxTRSkNCiMgYXhpcygxKTsgYXhpcygyKQ0KIyBmb3IgKHMgaW4gMjpuc2ltKXsNCiMgICBsaW5lcyhyWyFpcy5uYShhbGl2ZVssc10pLHNdLCBsd2Q9MC41LCBjb2w9ImxpZ2h0Z3JleSIpDQojIH0NCiMgbGluZXMoYXBwbHkociwgMSwgbWVhbiwgbmEucm09VFJVRSksIGx3ZD0xLjUpDQojIG10ZXh0KCJBIiwgYXQ9MCwgY2V4PTEuNSkNCiMgYSA8LSBoaXN0KG1lYW4uciwgbmNsYXNzPTUwLCBjb2w9ImRvZGdlcmJsdWUiLCBtYWluPSIiLA0KIyAgICAgeGxhYj0iUG9wdWxhdGlvbiBncm93dGggcmF0ZSIsIGF4ZXM9RkFMU0UpICN4bGltPWMoLTIuNSwgMC4xKSwgDQojIGF4aXMoMSkNCiMgYXhpcygyLCBhdD1jKDAsIDUwMDAsIDEwMDAwLCAxNTAwMCwgMjAwMDAsIDI1MDAwLCAzMDAwMCksIGxhYmVscz1jKDAsIDUsIDEwLCAxNSwgMjAsIDI1LCAzMCkpDQojIG10ZXh0KCJCIiwgYXQ9YSRtaWRzWzFdLCBjZXg9MS41KQ0KIyBhIDwtIGhpc3QobWVhbi5yW25vdC5leHRpbmN0XSwgbmNsYXNzPTI1LCBjb2w9ImRvZGdlcmJsdWUiLCBtYWluPSIiLA0KIyAgICAgeGxhYj0iUG9wdWxhdGlvbiBncm93dGggcmF0ZSIsIGF4ZXM9RkFMU0UpDQojIGF4aXMoMSkNCiMgYXhpcygyLCBhdD1jKDAsIDIwMDAsIDQwMDAsIDYwMDAsIDgwMDAsIDEwMDAwKSwgbGFiZWxzPWMoMCwgMiwgNCwgNiwgOCwgMTApKQ0KIyBtdGV4dCgiQyIsIGF0PWEkbWlkc1sxXSwgY2V4PTEuNSkNCiMgcGFyKG9wKQ0KIyB+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fg0KDQojIGh0dHBzOi8vZ2l0aHViLmNvbS9taWtlbWVyZWRpdGgvSVBNX2NvZGUvYmxvYi9tYWluL0lQTV8wMy9JUE1fMDMuMy41LlINCg0KDQpgYGANCg0KDQojIyMjIE1lZGl1bSBUcmVhdG1lbnQgc2ltdWxhdGlvbnMgIA0KDQoNCmBgYHtyLCBmaWcuaGVpZ2h0PTEwLCBmaWcud2lkdGg9MTB9DQoNCiMgaHR0cHM6Ly9naXRodWIuY29tL21pa2VtZXJlZGl0aC9JUE1fY29kZS9ibG9iL21haW4vSVBNXzAzL0lQTV8wMy4zLjUuUg0KDQojIDMuMyBDbGFzc2ljYWwgYW5hbHlzaXMgb2YgYSBtYXRyaXggcG9wdWxhdGlvbiBtb2RlbA0KIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0NCg0KIyAzLjMuNSBBbmFseXNpcyBvZiBhIG1hdHJpeCBwb3B1bGF0aW9uIG1vZGVsIHdpdGggZGlmZmVyZW50IHNvdXJjZXMgb2YNCiMgICAgICAgc3RvY2hhc3RpY2l0eSBhbmQgcGFyYW1ldGVyIHVuY2VydGFpbnR5DQojIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLQ0KDQojIERlZmluZSBtZWFuLCBtZWFzdXJlbWVudCBlcnJvciBhbmQgdGVtcG9yYWwgdmFyaWFiaWxpdHkgb2YgdGhlIGRlbW9ncmFwaGljIHBhcmFtZXRlcnMNCm1lYW4uc2ogPC0gMC4xMTYzNjE1ICAgICAgICAgICMgTWVhbiB2YWx1ZSBvZiBqdXYuIHN1cnZpdmFsDQpzZC5zai5lIDwtIDAuMDU1NDU4OCAgICAgICAgIyBVbmNlcnRhaW50eSBvZiBtZWFuIGp1di4gc3Vydml2YWwgYXMgU0Qgb24gbmF0dXJhbCBzY2FsZQ0Kc2Quc2oudCA8LSBwbG9naXMoMC4wMzMwNDAzOCkgICAgICAgICAjIHBvcHVsYXRpb24gdmFyaWFiaWxpdHkgb2YganV2LiBzdXJ2aXZhbCBhcyBTRCBvbiBsb2dpdCBzY2FsZSAjIEFuZHJldywgdGhpcyBtaWdodCBoYXZlIHRvIGJlIHBsb2dpcygwLjAzMzA0MDM4KSwgYnV0IG5vdCBzdXJlLCBjaGVjayB0aGUgdGV4dC4NCm1lYW4uc2EgPC0gMC41MjIyICAgICAgICAgIyBNZWFuIHZhbHVlIG9mIGFkLiBzdXJ2aXZhbA0Kc2Quc2EuZSA8LSAwLjA1NzY5NjkzICAgICAgICAjIFVuY2VydGFpbnR5IG9mIG1lYW4gYWQuIHN1cnZpdmFsIGFzIFNEIG9uIG5hdHVyYWwgc2NhbGUNCnNkLnNhLnQgPC0gcGxvZ2lzKDAuMDM4NjIyMSkgICAgICAgICAjIFRlbXBvcmFsIHZhcmlhYmlsaXR5IG9mIGFkLiBzdXJ2aXZhbCBhcyBTRCBvbiBsb2dpdCBzY2FsZQ0KbWVhbi5mMSA8LSAxLjYwNSAgICAgICAgICAjIE1lYW4gdmFsdWUgb2YgcHJvZHVjdGl2aXR5IG9mIDF5IGZlbWFsZXMNCnNkLmYxLmUgPC0gMC4xMzI2MDMyICAgICAgICAgIyBVbmNlcnRhaW50eSBvZiBtZWFuIHByb2R1Y3Rpdml0eSBhcyBTRCBvbiBuYXR1cmFsIHNjYWxlDQpzZC5mMS50IDwtIDAuMTAxNDQ3OSAgICAgICAgICAjIFRlbXBvcmFsIHZhcmlhYmlsaXR5IG9mIHByb2R1Y3Rpdml0eSBhcyBTRCBvbiBuYXR1cmFsIHNjYWxlDQptZWFuLmZhIDwtIDEuNjA1ICAgICAgICAgICMgTWVhbiB2YWx1ZSBvZiBwcm9kdWN0aXZpdHkgb2YgYWR1bHQgZmVtYWxlcw0Kc2QuZmEuZSA8LSAwLjEzMjYwMzIgICAgICAgICAjIFVuY2VydGFpbnR5IG9mIG1lYW4gcHJvZHVjdGl2aXR5IGFzIFNEIG9uIG5hdHVyYWwgc2NhbGUNCnNkLmZhLnQgPC0gMC4xMDEgICAgICAgICAgIyBUZW1wb3JhbCB2YXJpYWJpbGl0eSBvZiBwcm9kdWN0aXZpdHkgYXMgU0Qgb24gbmF0dXJhbCBzY2FsZQ0KbWVhbi5pbW0gPC0gMC4xOTI1ODcgICAgICAjIE1lYW4gdmFsdWUgb2YgYWR1bHQgaW1taWdyYXRpb24gIA0Kc2QuaW1tLmUgPC0gMC4wNjY3NDgwOSAgICAjIFVuY2VydGFpbnR5IG9mIG1lYW4gYWR1bHQgaW1taWdyYXRpb24gYXMgU0Qgb24gbmF0dXJhbCBzY2FsZQ0Kc2QuaW1tLnQgPC0gMC4wMjg3MjI4MSAgICAjIHBvcHVsYXRpb24gdmFyaWFiaWxpdHkgb2YgYWR1bHQgaW1taWdyYXRpb24gYXMgU0Qgb24gbmF0cnVhbCBzY2FsZQ0KDQojIERlZmluZSB0aGUgbnVtYmVyIG9mIHllYXJzIHdpdGggcHJlZGljdGlvbnMgYW5kIHRoZSBNb250ZSBDYXJsbyBzZXR0aW5nDQpUIDwtIDEwICAgICAgICAgICAgICAgICMgTnVtYmVyIG9mIHllYXJzIChwcm9qZWN0aW9uIHRpbWUgZnJhbWUpDQpuc2ltIDwtIDEwMDAwICAgICAgICAgICMgTnVtYmVyIG9mIHJlcGxpY2F0ZSBwb3B1bGF0aW9ucyBzaW11bGF0ZWQNCg0KIyBEZWZpbmUgcG9wdWxhdGlvbiBtYXRyaXggYW5kIGluaXRpYWwgc3RhZ2Utc3BlY2lmaWMgcG9wdWxhdGlvbiBzaXplcw0KTiA8LSBhcnJheShOQSwgZGltPWMoMiwgVCsxLCBuc2ltKSkNCk5bLDEsXSA8LSBjKDMsMSkNCnIgPC0gbWF0cml4KE5BLCBucm93PVQsIG5jb2w9bnNpbSkNCmFsaXZlIDwtIG1hdHJpeChOQSwgbnJvdz1ULCBuY29sPW5zaW0pDQptZWFuLnIgPC0gbnVtZXJpYyhuc2ltKQ0KDQojIFByb2plY3QgcG9wdWxhdGlvbg0KZm9yIChzIGluIDE6bnNpbSl7ICMgTG9vcCBvdmVyIHJlcGxpY2F0ZSBwb3B1bGF0aW9ucw0KICAjaWYocyAlJSAxMDAgPT0gMCkge2NhdChwYXN0ZSgiKioqIFNpbXJlcCIsIHMsICIqKipcbiIpKSB9ICAgIyBDb3VudGVyDQogICMgR2VuZXJhdGUgYSBtZWFuIG9mIHRoZSBkZW1vZ3JhcGhpYyByYXRlcyAoc3ViamVjdCB0byBtZWFzdXJlbWVudCBlcnJvcikNCiAgbXNqIDwtIHJiZXRhMigxLCBtZWFuLnNqLCBzZC5zai5lKQ0KICBtc2EgPC0gcmJldGEyKDEsIG1lYW4uc2EsIHNkLnNhLmUpDQogIG1mMSA8LSBybm9ybSgxLCBtZWFuLmYxLCBzZC5mMS5lKQ0KICBtZmEgPC0gcm5vcm0oMSwgbWVhbi5mYSwgc2QuZmEuZSkNCiAgbWlhIDwtIHJub3JtKDEsIG1lYW4uaW1tLCBzZC5pbW0uZSkNCg0KICAjIEdlbmVyYXRlIGFubnVhbCBkZW1vZ3JhcGhpYyByYXRlcyAoc3ViamVjdCB0byB0ZW1wb3JhbCB2YXJpYWJpbGl0eSkNCiAgc2ogPC0gcGxvZ2lzKHJub3JtKFQsIHFsb2dpcyhtc2opLCBzZC5zai50KSkNCiAgc2EgPC0gcGxvZ2lzKHJub3JtKFQsIHFsb2dpcyhtc2EpLCBzZC5zYS50KSkNCiAgZjEgPC0gcG1heCgwLCBybm9ybShULCBtZjEsIHNkLmYxLnQpKSAgICAgICAgICAgICAgICAgICAgICAgIyBBdm9pZHMgbmVnYXRpdmUgdmFsdWVzDQogIGZhIDwtIHBtYXgoMCwgcm5vcm0oVCwgbWZhLCBzZC5mYS50KSkgICAgICAgICAgICAgICAgICAgICAgICMgRGl0dG8NCiAgaWEgPC0gcG1heCgwLCBybm9ybShULCBtaWEsIHNkLmltbS50KSkgICAgICAgICAgICAgICAgICAgICAgICMgRGl0dG8NCg0KICAjIFByb2plY3QgcG9wdWxhdGlvbiAoaW5jbHVkZSBkZW1vZ3JhcGhpYyBzdG9jaGFzdGljaXR5KQ0KICBmb3IgKHQgaW4gMTpUKXsgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAjIExvb3Agb3ZlciB5ZWFycw0KICAgIE5bMSx0KzEsc10gPC0gcnBvaXMoMSwgc2pbdF0gKiAoZjFbdF0gKiBOWzEsdCxzXSArIGZhW3RdICogTlsyLHQsc10pKQ0KICAgIE5bMix0KzEsc10gPC0gcmJpbm9tKDEsIHN1bShOWyx0LHNdKSwgc2FbdF0pK3Jwb2lzKDEsaWEpDQogICAgaWYgKHN1bShOWyx0KzEsc10pID09IDApIGJyZWFrDQogICAgI3JbdCxzXSA8LSBsb2coc3VtKE5bLHQrMSxzXSkpIC0gbG9nKHN1bShOWyx0LHNdKSkNCiAgICBhbGl2ZVt0LHNdIDwtIHQNCiAgfSAjdA0KICAjbWVhbi5yW3NdIDwtIG1lYW4oclttaW4oYWxpdmVbLHNdLCBuYS5ybT1UUlVFKTptYXgoYWxpdmVbLHNdLCBuYS5ybT1UUlVFKSxzXSkNCn0gDQoNCiNtZWFuKG1lYW4ucikNCg0KI3NkKG1lYW4ucikNCg0KDQpub3QuZXh0aW5jdCA8LSB3aGljaCghaXMubmEoYWxpdmVbVCxdKSkNCm1lYW4obWVhbi5yW25vdC5leHRpbmN0XSkNCg0Kc2QobWVhbi5yW25vdC5leHRpbmN0XSkNCg0KIyBFeHRpbmN0aW9uIHByb2JhYmlsaXR5IChhZnRlciBUIHllYXJzKQ0Kc3VtKGlzLm5hKGFsaXZlW1QsXSkpIC8gbnNpbQ0KDQpyb3dTdW1zKGlzLm5hKGFsaXZlKSkgLyBuc2ltDQoNCmRmIDwtIGRhdGEuZnJhbWUoDQogIHRvdGFsY291bnQ9Yyhjb2xTdW1zKE5bLCwxOm5zaW1dKSksDQogIHRpbWU9cmVwKGMoMDpUKSxuc2ltKSwNCiAgc2ltbnVtYmVyPWdsKG5zaW0sIFQrMSkNCikNCg0KDQojIHBsb3Qoaml0dGVyKGMoY29sU3VtcyhOWywsMTpuc2ltXSkpLDEpfmppdHRlcihyZXAoYygwOlQpLG5zaW0pLDEpLCBwY2g9MykNCiMgYm94cGxvdChjKGNvbFN1bXMoTlssLDE6bnNpbV0pKX5mYWN0b3IocmVwKGMoMDpUKSxuc2ltKSkpDQogYnhwb2JqPC1ib3hwbG90KGMoY29sU3VtcyhOWywsMTpuc2ltXSkpfmZhY3RvcihyZXAoYygwOlQpLG5zaW0pKSwgcGxvdD1GKQ0KIyBwbG90KGppdHRlcihjKGNvbFN1bXMoTlssLDE6bnNpbV0pKSwxKX5qaXR0ZXIocmVwKGMoMDpUKSxuc2ltKSwxKSwgcGNoPTMpDQojIHBvaW50cyhieHBvYmokc3RhdHNbMyxdfmMoMDpUKSwgdHlwZT0ibCIsIGNvbD0icmVkIiwgbHdkPTIpDQojIA0KIyBwYXIobWFpPWMoMSwxLDAuMSwxKSkNCiMgcGxvdChqaXR0ZXIoYyhjb2xTdW1zKE5bLCwxOm5zaW1dKSksMSl+aml0dGVyKHJlcChjKDA6VCksbnNpbSksMSksIHBjaD0zKQ0KIyBwb2ludHMoYnhwb2JqJHN0YXRzWzMsXX5jKDA6VCksIHR5cGU9ImIiLCBjb2w9ImJsdWUiLCBsd2Q9MiwgcGNoPTE2KQ0KIyBwYXIobmV3PVQpDQojIHBsb3QoYyhyb3dTdW1zKGlzLm5hKGFsaXZlKSkvbnNpbSl+YygxOlQpLCB0eXBlPSJiIiwgY29sPSJyZWQiLCBidHk9Im4iLCB4bGFiPSIiLCB5bGFiPSIiLCBheGVzPUYsIHlsaW09YygwLDEpLCB4bGltPWMoMCxUKSwgbHdkPTIsIHBjaD0xNikNCiMgYXhpcyhzaWRlPTQsIGF0PXByZXR0eShyYW5nZShjKDAsMSkpKSkNCiMgbXRleHQoInByb2JhYmlsaXR5IG9mIGV4dGluY3Rpb24iLCBzaWRlPTQsIGxpbmU9MykNCg0KcGFyKG1haT1jKDEsMSwwLjEsMSkpDQpwbG90KGppdHRlcihjKGNvbFN1bXMoTlssLDE6bnNpbV0pKSwxKX5qaXR0ZXIocmVwKGMoMDpUKSxuc2ltKSwxKSwgcGNoPTMsIHhsYWI9InllYXJzIG9mIHNpbXVsYXRpb24iLCB5bGFiPSJlc3RpbWF0ZWQgcG9wdWxhdGlvbiBzaXplIikNCnBvaW50cyhieHBvYmokc3RhdHNbMyxdfmMoMDpUKSwgdHlwZT0iYiIsIGNvbD0iYmx1ZSIsIGx3ZD0yLCBwY2g9MTYpDQpwYXIobmV3PVQpDQpwbG90KGMocm93U3Vtcyhpcy5uYShhbGl2ZSkpL25zaW0pfmMoMTpUKSwgdHlwZT0iYiIsIGNvbD0icmVkIiwgYnR5PSJuIiwgeGxhYj0iIiwgeWxhYj0iIiwgYXhlcz1GLCB5bGltPWMoMCwxKSwgeGxpbT1jKDAsVCksIGx3ZD0yLCBwY2g9MTYpDQpheGlzKHNpZGU9NCwgYXQ9cHJldHR5KHJhbmdlKGMoMCwxKSkpKQ0KbXRleHQoInByb3BvcnRpb24gb2Ygc2ltdWxhdGlvbnMgcmVhY2hlZCBOPTAiLCBzaWRlPTQsIGxpbmU9MywgY29sPSJyZWQiKQ0KDQoNCg0KZ2dwbG90KCkrDQogZ2VvbV9saW5lKGRhdGE9ZGYsIGFlcyh4PXRpbWUsIHk9dG90YWxjb3VudCwgZ3JvdXA9c2ltbnVtYmVyKSwgbGluZXdpZHRoPTEsIGNvbG9yPSJncmF5IiwgYWxwaGE9MC44KSArDQogZ2VvbV9saW5lKGFlcyh4PWMoMDpUKSwgeT1ieHBvYmokc3RhdHNbMyxdKSwgY29sb3I9ImJsdWUiLCBsaW5ld2lkdGg9MykrDQogI2dlb21fbGluZShhZXMoeD1jKDE6VCksIHk9Yyhyb3dTdW1zKGlzLm5hKGFsaXZlKSkvbnNpbSkpLCBjb2w9InJlZCIsIGxpbmV3aWR0aD0yKSsNCiBnZW9tX2xhYmVsKGFlcyh4PWMoMTpUKSwgeT0wLCBsYWJlbD1yb3VuZChjKHJvd1N1bXMoaXMubmEoYWxpdmUpKS9uc2ltKSwgMikpLCBjb2xvcj0icmVkIikrDQogc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDE6MTApKStzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLDUwLCBieT0yKSkrDQogdGhlbWVfY2xhc3NpYyhiYXNlX3NpemU9MjIpICsNCiBsYWJzKHg9IlllYXJzIG9mIHNpbXVsYXRlZCBwb3B1bGF0aW9uIHNpemUgYW5kXG5wcm9wb3J0aW9uIG9mIHNpbXVsYXRpb25zIHdpdGggTj0wIiwgeT0iVG90YWwgc2ltdWxhdGVkIHBvcHVsYXRpb24gY291bnQiKQ0KDQpnZ3Bsb3QoKSsNCiAgZ2VvbV9qaXR0ZXIoZGF0YT1kZiwgYWVzKHg9dGltZSwgeT10b3RhbGNvdW50LCBncm91cD1zaW1udW1iZXIpLCBzaGFwZT0iLiIsIHdpZHRoPTAuMywgaGVpZ2h0PTAuMykgKw0KICBnZW9tX2xpbmUoYWVzKHg9YygwOlQpLCB5PWJ4cG9iaiRzdGF0c1szLF0pLCBjb2xvcj0iYmx1ZSIsIGxpbmV3aWR0aD0zKSsNCiAgI2dlb21fbGluZShhZXMoeD1jKDE6VCksIHk9Yyhyb3dTdW1zKGlzLm5hKGFsaXZlKSkvbnNpbSkpLCBjb2w9InJlZCIsIGxpbmV3aWR0aD0yKSsNCiAgZ2VvbV9sYWJlbChhZXMoeD1jKDE6VCksIHk9LTAuNSwgbGFiZWw9cm91bmQoYyhyb3dTdW1zKGlzLm5hKGFsaXZlKSkvbnNpbSksIDIpKSwgY29sb3I9InJlZCIpKw0KICBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMToxMCkpK3NjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsNTAsIGJ5PTIpKSsNCiAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemU9MjIpKw0KICBsYWJzKHg9IlllYXJzIG9mIHNpbXVsYXRlZCBwb3B1bGF0aW9uIHNpemUgYW5kXG5wcm9wb3J0aW9uIG9mIHNpbXVsYXRpb25zIHdpdGggTj0wIiwgeT0iVG90YWwgc2ltdWxhdGVkIHBvcHVsYXRpb24gY291bnQiKQ0KDQojIGdncGxvdCgpKw0KIyAgIGdlb21faGV4KGRhdGE9ZGYsIGFlcyh4PXRpbWUsIHk9dG90YWxjb3VudCwgZ3JvdXA9c2ltbnVtYmVyKSwgYmlucz0xMCkgKw0KIyAgIGdlb21fbGluZShhZXMoeD1jKDA6VCksIHk9Ynhwb2JqJHN0YXRzWzMsXSksIGNvbG9yPSJibHVlIiwgbGluZXdpZHRoPTMpKw0KIyAgICNnZW9tX2xpbmUoYWVzKHg9YygxOlQpLCB5PWMocm93U3Vtcyhpcy5uYShhbGl2ZSkpL25zaW0pKSwgY29sPSJyZWQiLCBsaW5ld2lkdGg9MikrDQojICAgZ2VvbV9sYWJlbChhZXMoeD1jKDE6VCksIHk9LTAuNSwgbGFiZWw9cm91bmQoYyhyb3dTdW1zKGlzLm5hKGFsaXZlKSkvbnNpbSksIDIpKSwgY29sb3I9InJlZCIpKw0KIyAgIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygxOjEwKSkrc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCw1MCwgYnk9MikpKw0KIyAgIHRoZW1lX2NsYXNzaWMoYmFzZV9zaXplPTIyKSsNCiMgICBsYWJzKHg9IlllYXJzIG9mIHNpbXVsYXRlZCBwb3B1bGF0aW9uIHNpemUgYW5kXG5wcm9wb3J0aW9uIG9mIHNpbXVsYXRpb25zIHdpdGggTj0wIiwgeT0iVG90YWwgc2ltdWxhdGVkIHBvcHVsYXRpb24gY291bnQiKQ0KDQoNCiMgfn5+fiBQbG90IGdyYXBoIHdpdGggcG9wdWxhdGlvbiBncm93dGggcmF0ZXMgKEZpZy4gMy4xNSkgIH5+fn4NCiMgb3AgPC0gcGFyKG1hcj1jKDQsIDQsIDIsIDEpLCBsYXM9MSwgY2V4PTEuMSwgIm1mcm93IikNCiMgbGF5b3V0KG1hdHJpeChjKDEsIDEsIDIsIDMpLCAyLCAyLCBieXJvdz1UUlVFKSwgd2lkdGhzPWMoMSwgMSksIGhlaWdodHM9YygxLCAxKSwgVFJVRSkNCiMgcGxvdChyWywxXSwgdHlwZT0ibCIsIGx3ZD0wLjUsIHlsYWI9IkFubnVhbCBwb3B1bGF0aW9uIGdyb3d0aCByYXRlIiwgeGxhYj0iVGltZSIsDQojICAgICB5bGltPXJhbmdlKHJbd2hpY2goIWlzLm5hKGFsaXZlKSldKSwgY29sPSJsaWdodGdyZXkiLCBheGVzPUZBTFNFKQ0KIyBheGlzKDEpOyBheGlzKDIpDQojIGZvciAocyBpbiAyOm5zaW0pew0KIyAgIGxpbmVzKHJbIWlzLm5hKGFsaXZlWyxzXSksc10sIGx3ZD0wLjUsIGNvbD0ibGlnaHRncmV5IikNCiMgfQ0KIyBsaW5lcyhhcHBseShyLCAxLCBtZWFuLCBuYS5ybT1UUlVFKSwgbHdkPTEuNSkNCiMgbXRleHQoIkEiLCBhdD0wLCBjZXg9MS41KQ0KIyBhIDwtIGhpc3QobWVhbi5yLCBuY2xhc3M9NTAsIGNvbD0iZG9kZ2VyYmx1ZSIsIG1haW49IiIsDQojICAgICB4bGFiPSJQb3B1bGF0aW9uIGdyb3d0aCByYXRlIiwgYXhlcz1GQUxTRSkgI3hsaW09YygtMi41LCAwLjEpLCANCiMgYXhpcygxKQ0KIyBheGlzKDIsIGF0PWMoMCwgNTAwMCwgMTAwMDAsIDE1MDAwLCAyMDAwMCwgMjUwMDAsIDMwMDAwKSwgbGFiZWxzPWMoMCwgNSwgMTAsIDE1LCAyMCwgMjUsIDMwKSkNCiMgbXRleHQoIkIiLCBhdD1hJG1pZHNbMV0sIGNleD0xLjUpDQojIGEgPC0gaGlzdChtZWFuLnJbbm90LmV4dGluY3RdLCBuY2xhc3M9MjUsIGNvbD0iZG9kZ2VyYmx1ZSIsIG1haW49IiIsDQojICAgICB4bGFiPSJQb3B1bGF0aW9uIGdyb3d0aCByYXRlIiwgYXhlcz1GQUxTRSkNCiMgYXhpcygxKQ0KIyBheGlzKDIsIGF0PWMoMCwgMjAwMCwgNDAwMCwgNjAwMCwgODAwMCwgMTAwMDApLCBsYWJlbHM9YygwLCAyLCA0LCA2LCA4LCAxMCkpDQojIG10ZXh0KCJDIiwgYXQ9YSRtaWRzWzFdLCBjZXg9MS41KQ0KIyBwYXIob3ApDQojIH5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+DQoNCiMgaHR0cHM6Ly9naXRodWIuY29tL21pa2VtZXJlZGl0aC9JUE1fY29kZS9ibG9iL21haW4vSVBNXzAzL0lQTV8wMy4zLjUuUg0KDQoNCmBgYA0KDQoNCg0KIyMjIyBIaWdoIFRyZWF0bWVudCBzaW11bGF0aW9ucyAgDQoNCg0KYGBge3IsIGZpZy5oZWlnaHQ9MTAsIGZpZy53aWR0aD0xMH0NCg0KIyBodHRwczovL2dpdGh1Yi5jb20vbWlrZW1lcmVkaXRoL0lQTV9jb2RlL2Jsb2IvbWFpbi9JUE1fMDMvSVBNXzAzLjMuNS5SDQoNCiMgMy4zIENsYXNzaWNhbCBhbmFseXNpcyBvZiBhIG1hdHJpeCBwb3B1bGF0aW9uIG1vZGVsDQojID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PQ0KDQojIDMuMy41IEFuYWx5c2lzIG9mIGEgbWF0cml4IHBvcHVsYXRpb24gbW9kZWwgd2l0aCBkaWZmZXJlbnQgc291cmNlcyBvZg0KIyAgICAgICBzdG9jaGFzdGljaXR5IGFuZCBwYXJhbWV0ZXIgdW5jZXJ0YWludHkNCiMgLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tDQoNCiMgRGVmaW5lIG1lYW4sIG1lYXN1cmVtZW50IGVycm9yIGFuZCB0ZW1wb3JhbCB2YXJpYWJpbGl0eSBvZiB0aGUgZGVtb2dyYXBoaWMgcGFyYW1ldGVycw0KbWVhbi5zaiA8LSAwLjExNjM2MTUgICAgICAgICAgIyBNZWFuIHZhbHVlIG9mIGp1di4gc3Vydml2YWwNCnNkLnNqLmUgPC0gMC4wNTU0NTg4ICAgICAgICAjIFVuY2VydGFpbnR5IG9mIG1lYW4ganV2LiBzdXJ2aXZhbCBhcyBTRCBvbiBuYXR1cmFsIHNjYWxlDQpzZC5zai50IDwtIHBsb2dpcygwLjAzMzA0MDM4KSAgICAgICAgICMgcG9wdWxhdGlvbiB2YXJpYWJpbGl0eSBvZiBqdXYuIHN1cnZpdmFsIGFzIFNEIG9uIGxvZ2l0IHNjYWxlICMgQW5kcmV3LCB0aGlzIG1pZ2h0IGhhdmUgdG8gYmUgcGxvZ2lzKDAuMDMzMDQwMzgpLCBidXQgbm90IHN1cmUsIGNoZWNrIHRoZSB0ZXh0Lg0KbWVhbi5zYSA8LSAwLjUyMjIgICAgICAgICAjIE1lYW4gdmFsdWUgb2YgYWQuIHN1cnZpdmFsDQpzZC5zYS5lIDwtIDAuMDU3Njk2OTMgICAgICAgICMgVW5jZXJ0YWludHkgb2YgbWVhbiBhZC4gc3Vydml2YWwgYXMgU0Qgb24gbmF0dXJhbCBzY2FsZQ0Kc2Quc2EudCA8LSBwbG9naXMoMC4wMzg2MjIxKSAgICAgICAgICMgVGVtcG9yYWwgdmFyaWFiaWxpdHkgb2YgYWQuIHN1cnZpdmFsIGFzIFNEIG9uIGxvZ2l0IHNjYWxlDQptZWFuLmYxIDwtIDAuMzQzICAgICAgICAgICMgTWVhbiB2YWx1ZSBvZiBwcm9kdWN0aXZpdHkgb2YgMXkgZmVtYWxlcw0Kc2QuZjEuZSA8LSAwLjEzMjYwMzIgICAgICAgICAjIFVuY2VydGFpbnR5IG9mIG1lYW4gcHJvZHVjdGl2aXR5IGFzIFNEIG9uIG5hdHVyYWwgc2NhbGUNCnNkLmYxLnQgPC0gMC4xMDE0NDc5ICAgICAgICAgICMgVGVtcG9yYWwgdmFyaWFiaWxpdHkgb2YgcHJvZHVjdGl2aXR5IGFzIFNEIG9uIG5hdHVyYWwgc2NhbGUNCm1lYW4uZmEgPC0gMC4zNDMgICAgICAgICAgIyBNZWFuIHZhbHVlIG9mIHByb2R1Y3Rpdml0eSBvZiBhZHVsdCBmZW1hbGVzDQpzZC5mYS5lIDwtIDAuMTMyNjAzMiAgICAgICAgICMgVW5jZXJ0YWludHkgb2YgbWVhbiBwcm9kdWN0aXZpdHkgYXMgU0Qgb24gbmF0dXJhbCBzY2FsZQ0Kc2QuZmEudCA8LSAwLjEwMSAgICAgICAgICAjIFRlbXBvcmFsIHZhcmlhYmlsaXR5IG9mIHByb2R1Y3Rpdml0eSBhcyBTRCBvbiBuYXR1cmFsIHNjYWxlDQptZWFuLmltbSA8LSAwLjE5MjU4NyAgICAgICMgTWVhbiB2YWx1ZSBvZiBhZHVsdCBpbW1pZ3JhdGlvbiAgDQpzZC5pbW0uZSA8LSAwLjA2Njc0ODA5ICAgICMgVW5jZXJ0YWludHkgb2YgbWVhbiBhZHVsdCBpbW1pZ3JhdGlvbiBhcyBTRCBvbiBuYXR1cmFsIHNjYWxlDQpzZC5pbW0udCA8LSAwLjAyODcyMjgxICAgICMgcG9wdWxhdGlvbiB2YXJpYWJpbGl0eSBvZiBhZHVsdCBpbW1pZ3JhdGlvbiBhcyBTRCBvbiBuYXRydWFsIHNjYWxlDQoNCiMgRGVmaW5lIHRoZSBudW1iZXIgb2YgeWVhcnMgd2l0aCBwcmVkaWN0aW9ucyBhbmQgdGhlIE1vbnRlIENhcmxvIHNldHRpbmcNClQgPC0gMTAgICAgICAgICAgICAgICAgIyBOdW1iZXIgb2YgeWVhcnMgKHByb2plY3Rpb24gdGltZSBmcmFtZSkNCm5zaW0gPC0gMTAwMDAgICAgICAgICAgIyBOdW1iZXIgb2YgcmVwbGljYXRlIHBvcHVsYXRpb25zIHNpbXVsYXRlZA0KDQojIERlZmluZSBwb3B1bGF0aW9uIG1hdHJpeCBhbmQgaW5pdGlhbCBzdGFnZS1zcGVjaWZpYyBwb3B1bGF0aW9uIHNpemVzDQpOIDwtIGFycmF5KE5BLCBkaW09YygyLCBUKzEsIG5zaW0pKQ0KTlssMSxdIDwtIGMoMywxKQ0KciA8LSBtYXRyaXgoTkEsIG5yb3c9VCwgbmNvbD1uc2ltKQ0KYWxpdmUgPC0gbWF0cml4KE5BLCBucm93PVQsIG5jb2w9bnNpbSkNCm1lYW4uciA8LSBudW1lcmljKG5zaW0pDQoNCiMgUHJvamVjdCBwb3B1bGF0aW9uDQpmb3IgKHMgaW4gMTpuc2ltKXsgIyBMb29wIG92ZXIgcmVwbGljYXRlIHBvcHVsYXRpb25zDQogICNpZihzICUlIDEwMCA9PSAwKSB7Y2F0KHBhc3RlKCIqKiogU2ltcmVwIiwgcywgIioqKlxuIikpIH0gICAjIENvdW50ZXINCiAgIyBHZW5lcmF0ZSBhIG1lYW4gb2YgdGhlIGRlbW9ncmFwaGljIHJhdGVzIChzdWJqZWN0IHRvIG1lYXN1cmVtZW50IGVycm9yKQ0KICBtc2ogPC0gcmJldGEyKDEsIG1lYW4uc2osIHNkLnNqLmUpDQogIG1zYSA8LSByYmV0YTIoMSwgbWVhbi5zYSwgc2Quc2EuZSkNCiAgbWYxIDwtIHJub3JtKDEsIG1lYW4uZjEsIHNkLmYxLmUpDQogIG1mYSA8LSBybm9ybSgxLCBtZWFuLmZhLCBzZC5mYS5lKQ0KICBtaWEgPC0gcm5vcm0oMSwgbWVhbi5pbW0sIHNkLmltbS5lKQ0KDQogICMgR2VuZXJhdGUgYW5udWFsIGRlbW9ncmFwaGljIHJhdGVzIChzdWJqZWN0IHRvIHRlbXBvcmFsIHZhcmlhYmlsaXR5KQ0KICBzaiA8LSBwbG9naXMocm5vcm0oVCwgcWxvZ2lzKG1zaiksIHNkLnNqLnQpKQ0KICBzYSA8LSBwbG9naXMocm5vcm0oVCwgcWxvZ2lzKG1zYSksIHNkLnNhLnQpKQ0KICBmMSA8LSBwbWF4KDAsIHJub3JtKFQsIG1mMSwgc2QuZjEudCkpICAgICAgICAgICAgICAgICAgICAgICAjIEF2b2lkcyBuZWdhdGl2ZSB2YWx1ZXMNCiAgZmEgPC0gcG1heCgwLCBybm9ybShULCBtZmEsIHNkLmZhLnQpKSAgICAgICAgICAgICAgICAgICAgICAgIyBEaXR0bw0KICBpYSA8LSBwbWF4KDAsIHJub3JtKFQsIG1pYSwgc2QuaW1tLnQpKSAgICAgICAgICAgICAgICAgICAgICAgIyBEaXR0bw0KDQogICMgUHJvamVjdCBwb3B1bGF0aW9uIChpbmNsdWRlIGRlbW9ncmFwaGljIHN0b2NoYXN0aWNpdHkpDQogIGZvciAodCBpbiAxOlQpeyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICMgTG9vcCBvdmVyIHllYXJzDQogICAgTlsxLHQrMSxzXSA8LSBycG9pcygxLCBzalt0XSAqIChmMVt0XSAqIE5bMSx0LHNdICsgZmFbdF0gKiBOWzIsdCxzXSkpDQogICAgTlsyLHQrMSxzXSA8LSByYmlub20oMSwgc3VtKE5bLHQsc10pLCBzYVt0XSkrcnBvaXMoMSxpYSkNCiAgICBpZiAoc3VtKE5bLHQrMSxzXSkgPT0gMCkgYnJlYWsNCiAgICAjclt0LHNdIDwtIGxvZyhzdW0oTlssdCsxLHNdKSkgLSBsb2coc3VtKE5bLHQsc10pKQ0KICAgIGFsaXZlW3Qsc10gPC0gdA0KICB9ICN0DQogICNtZWFuLnJbc10gPC0gbWVhbihyW21pbihhbGl2ZVssc10sIG5hLnJtPVRSVUUpOm1heChhbGl2ZVssc10sIG5hLnJtPVRSVUUpLHNdKQ0KfSANCg0KI21lYW4obWVhbi5yKQ0KDQojc2QobWVhbi5yKQ0KDQoNCm5vdC5leHRpbmN0IDwtIHdoaWNoKCFpcy5uYShhbGl2ZVtULF0pKQ0KbWVhbihtZWFuLnJbbm90LmV4dGluY3RdKQ0KDQpzZChtZWFuLnJbbm90LmV4dGluY3RdKQ0KDQojIEV4dGluY3Rpb24gcHJvYmFiaWxpdHkgKGFmdGVyIFQgeWVhcnMpDQpzdW0oaXMubmEoYWxpdmVbVCxdKSkgLyBuc2ltDQoNCnJvd1N1bXMoaXMubmEoYWxpdmUpKSAvIG5zaW0NCg0KZGYgPC0gZGF0YS5mcmFtZSgNCiAgdG90YWxjb3VudD1jKGNvbFN1bXMoTlssLDE6bnNpbV0pKSwNCiAgdGltZT1yZXAoYygwOlQpLG5zaW0pLA0KICBzaW1udW1iZXI9Z2wobnNpbSwgVCsxKQ0KKQ0KDQoNCiMgcGxvdChqaXR0ZXIoYyhjb2xTdW1zKE5bLCwxOm5zaW1dKSksMSl+aml0dGVyKHJlcChjKDA6VCksbnNpbSksMSksIHBjaD0zKQ0KIyBib3hwbG90KGMoY29sU3VtcyhOWywsMTpuc2ltXSkpfmZhY3RvcihyZXAoYygwOlQpLG5zaW0pKSkNCiBieHBvYmo8LWJveHBsb3QoYyhjb2xTdW1zKE5bLCwxOm5zaW1dKSl+ZmFjdG9yKHJlcChjKDA6VCksbnNpbSkpLCBwbG90PUYpDQojIHBsb3Qoaml0dGVyKGMoY29sU3VtcyhOWywsMTpuc2ltXSkpLDEpfmppdHRlcihyZXAoYygwOlQpLG5zaW0pLDEpLCBwY2g9MykNCiMgcG9pbnRzKGJ4cG9iaiRzdGF0c1szLF1+YygwOlQpLCB0eXBlPSJsIiwgY29sPSJyZWQiLCBsd2Q9MikNCiMgDQojIHBhcihtYWk9YygxLDEsMC4xLDEpKQ0KIyBwbG90KGppdHRlcihjKGNvbFN1bXMoTlssLDE6bnNpbV0pKSwxKX5qaXR0ZXIocmVwKGMoMDpUKSxuc2ltKSwxKSwgcGNoPTMpDQojIHBvaW50cyhieHBvYmokc3RhdHNbMyxdfmMoMDpUKSwgdHlwZT0iYiIsIGNvbD0iYmx1ZSIsIGx3ZD0yLCBwY2g9MTYpDQojIHBhcihuZXc9VCkNCiMgcGxvdChjKHJvd1N1bXMoaXMubmEoYWxpdmUpKS9uc2ltKX5jKDE6VCksIHR5cGU9ImIiLCBjb2w9InJlZCIsIGJ0eT0ibiIsIHhsYWI9IiIsIHlsYWI9IiIsIGF4ZXM9RiwgeWxpbT1jKDAsMSksIHhsaW09YygwLFQpLCBsd2Q9MiwgcGNoPTE2KQ0KIyBheGlzKHNpZGU9NCwgYXQ9cHJldHR5KHJhbmdlKGMoMCwxKSkpKQ0KIyBtdGV4dCgicHJvYmFiaWxpdHkgb2YgZXh0aW5jdGlvbiIsIHNpZGU9NCwgbGluZT0zKQ0KDQpwYXIobWFpPWMoMSwxLDAuMSwxKSkNCnBsb3Qoaml0dGVyKGMoY29sU3VtcyhOWywsMTpuc2ltXSkpLDEpfmppdHRlcihyZXAoYygwOlQpLG5zaW0pLDEpLCBwY2g9MywgeGxhYj0ieWVhcnMgb2Ygc2ltdWxhdGlvbiIsIHlsYWI9ImVzdGltYXRlZCBwb3B1bGF0aW9uIHNpemUiKQ0KcG9pbnRzKGJ4cG9iaiRzdGF0c1szLF1+YygwOlQpLCB0eXBlPSJiIiwgY29sPSJibHVlIiwgbHdkPTIsIHBjaD0xNikNCnBhcihuZXc9VCkNCnBsb3QoYyhyb3dTdW1zKGlzLm5hKGFsaXZlKSkvbnNpbSl+YygxOlQpLCB0eXBlPSJiIiwgY29sPSJyZWQiLCBidHk9Im4iLCB4bGFiPSIiLCB5bGFiPSIiLCBheGVzPUYsIHlsaW09YygwLDEpLCB4bGltPWMoMCxUKSwgbHdkPTIsIHBjaD0xNikNCmF4aXMoc2lkZT00LCBhdD1wcmV0dHkocmFuZ2UoYygwLDEpKSkpDQptdGV4dCgicHJvcG9ydGlvbiBvZiBzaW11bGF0aW9ucyByZWFjaGVkIE49MCIsIHNpZGU9NCwgbGluZT0zLCBjb2w9InJlZCIpDQoNCg0KDQpnZ3Bsb3QoKSsNCiBnZW9tX2xpbmUoZGF0YT1kZiwgYWVzKHg9dGltZSwgeT10b3RhbGNvdW50LCBncm91cD1zaW1udW1iZXIpLCBsaW5ld2lkdGg9MSwgY29sb3I9ImdyYXkiLCBhbHBoYT0wLjgpICsNCiBnZW9tX2xpbmUoYWVzKHg9YygwOlQpLCB5PWJ4cG9iaiRzdGF0c1szLF0pLCBjb2xvcj0iYmx1ZSIsIGxpbmV3aWR0aD0zKSsNCiAjZ2VvbV9saW5lKGFlcyh4PWMoMTpUKSwgeT1jKHJvd1N1bXMoaXMubmEoYWxpdmUpKS9uc2ltKSksIGNvbD0icmVkIiwgbGluZXdpZHRoPTIpKw0KIGdlb21fbGFiZWwoYWVzKHg9YygxOlQpLCB5PTAsIGxhYmVsPXJvdW5kKGMocm93U3Vtcyhpcy5uYShhbGl2ZSkpL25zaW0pLCAyKSksIGNvbG9yPSJyZWQiKSsNCiBzY2FsZV94X2NvbnRpbnVvdXMoYnJlYWtzPWMoMToxMCkpK3NjYWxlX3lfY29udGludW91cyhicmVha3M9c2VxKDAsNTAsIGJ5PTIpKSsNCiB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZT0yMikgKw0KIGxhYnMoeD0iWWVhcnMgb2Ygc2ltdWxhdGVkIHBvcHVsYXRpb24gc2l6ZSBhbmRcbnByb3BvcnRpb24gb2Ygc2ltdWxhdGlvbnMgd2l0aCBOPTAiLCB5PSJUb3RhbCBzaW11bGF0ZWQgcG9wdWxhdGlvbiBjb3VudCIpDQoNCmdncGxvdCgpKw0KICBnZW9tX2ppdHRlcihkYXRhPWRmLCBhZXMoeD10aW1lLCB5PXRvdGFsY291bnQsIGdyb3VwPXNpbW51bWJlciksIHNoYXBlPSIuIiwgd2lkdGg9MC4zLCBoZWlnaHQ9MC4zKSArDQogIGdlb21fbGluZShhZXMoeD1jKDA6VCksIHk9Ynhwb2JqJHN0YXRzWzMsXSksIGNvbG9yPSJibHVlIiwgbGluZXdpZHRoPTMpKw0KICAjZ2VvbV9saW5lKGFlcyh4PWMoMTpUKSwgeT1jKHJvd1N1bXMoaXMubmEoYWxpdmUpKS9uc2ltKSksIGNvbD0icmVkIiwgbGluZXdpZHRoPTIpKw0KICBnZW9tX2xhYmVsKGFlcyh4PWMoMTpUKSwgeT0tMC41LCBsYWJlbD1yb3VuZChjKHJvd1N1bXMoaXMubmEoYWxpdmUpKS9uc2ltKSwgMikpLCBjb2xvcj0icmVkIikrDQogIHNjYWxlX3hfY29udGludW91cyhicmVha3M9YygxOjEwKSkrc2NhbGVfeV9jb250aW51b3VzKGJyZWFrcz1zZXEoMCw1MCwgYnk9MikpKw0KICB0aGVtZV9jbGFzc2ljKGJhc2Vfc2l6ZT0yMikrDQogIGxhYnMoeD0iWWVhcnMgb2Ygc2ltdWxhdGVkIHBvcHVsYXRpb24gc2l6ZSBhbmRcbnByb3BvcnRpb24gb2Ygc2ltdWxhdGlvbnMgd2l0aCBOPTAiLCB5PSJUb3RhbCBzaW11bGF0ZWQgcG9wdWxhdGlvbiBjb3VudCIpDQoNCiMgZ2dwbG90KCkrDQojICAgZ2VvbV9oZXgoZGF0YT1kZiwgYWVzKHg9dGltZSwgeT10b3RhbGNvdW50LCBncm91cD1zaW1udW1iZXIpLCBiaW5zPTEwKSArDQojICAgZ2VvbV9saW5lKGFlcyh4PWMoMDpUKSwgeT1ieHBvYmokc3RhdHNbMyxdKSwgY29sb3I9ImJsdWUiLCBsaW5ld2lkdGg9MykrDQojICAgI2dlb21fbGluZShhZXMoeD1jKDE6VCksIHk9Yyhyb3dTdW1zKGlzLm5hKGFsaXZlKSkvbnNpbSkpLCBjb2w9InJlZCIsIGxpbmV3aWR0aD0yKSsNCiMgICBnZW9tX2xhYmVsKGFlcyh4PWMoMTpUKSwgeT0tMC41LCBsYWJlbD1yb3VuZChjKHJvd1N1bXMoaXMubmEoYWxpdmUpKS9uc2ltKSwgMikpLCBjb2xvcj0icmVkIikrDQojICAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDE6MTApKStzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPXNlcSgwLDUwLCBieT0yKSkrDQojICAgdGhlbWVfY2xhc3NpYyhiYXNlX3NpemU9MjIpKw0KIyAgIGxhYnMoeD0iWWVhcnMgb2Ygc2ltdWxhdGVkIHBvcHVsYXRpb24gc2l6ZSBhbmRcbnByb3BvcnRpb24gb2Ygc2ltdWxhdGlvbnMgd2l0aCBOPTAiLCB5PSJUb3RhbCBzaW11bGF0ZWQgcG9wdWxhdGlvbiBjb3VudCIpDQoNCg0KIyB+fn5+IFBsb3QgZ3JhcGggd2l0aCBwb3B1bGF0aW9uIGdyb3d0aCByYXRlcyAoRmlnLiAzLjE1KSAgfn5+fg0KIyBvcCA8LSBwYXIobWFyPWMoNCwgNCwgMiwgMSksIGxhcz0xLCBjZXg9MS4xLCAibWZyb3ciKQ0KIyBsYXlvdXQobWF0cml4KGMoMSwgMSwgMiwgMyksIDIsIDIsIGJ5cm93PVRSVUUpLCB3aWR0aHM9YygxLCAxKSwgaGVpZ2h0cz1jKDEsIDEpLCBUUlVFKQ0KIyBwbG90KHJbLDFdLCB0eXBlPSJsIiwgbHdkPTAuNSwgeWxhYj0iQW5udWFsIHBvcHVsYXRpb24gZ3Jvd3RoIHJhdGUiLCB4bGFiPSJUaW1lIiwNCiMgICAgIHlsaW09cmFuZ2Uoclt3aGljaCghaXMubmEoYWxpdmUpKV0pLCBjb2w9ImxpZ2h0Z3JleSIsIGF4ZXM9RkFMU0UpDQojIGF4aXMoMSk7IGF4aXMoMikNCiMgZm9yIChzIGluIDI6bnNpbSl7DQojICAgbGluZXMoclshaXMubmEoYWxpdmVbLHNdKSxzXSwgbHdkPTAuNSwgY29sPSJsaWdodGdyZXkiKQ0KIyB9DQojIGxpbmVzKGFwcGx5KHIsIDEsIG1lYW4sIG5hLnJtPVRSVUUpLCBsd2Q9MS41KQ0KIyBtdGV4dCgiQSIsIGF0PTAsIGNleD0xLjUpDQojIGEgPC0gaGlzdChtZWFuLnIsIG5jbGFzcz01MCwgY29sPSJkb2RnZXJibHVlIiwgbWFpbj0iIiwNCiMgICAgIHhsYWI9IlBvcHVsYXRpb24gZ3Jvd3RoIHJhdGUiLCBheGVzPUZBTFNFKSAjeGxpbT1jKC0yLjUsIDAuMSksIA0KIyBheGlzKDEpDQojIGF4aXMoMiwgYXQ9YygwLCA1MDAwLCAxMDAwMCwgMTUwMDAsIDIwMDAwLCAyNTAwMCwgMzAwMDApLCBsYWJlbHM9YygwLCA1LCAxMCwgMTUsIDIwLCAyNSwgMzApKQ0KIyBtdGV4dCgiQiIsIGF0PWEkbWlkc1sxXSwgY2V4PTEuNSkNCiMgYSA8LSBoaXN0KG1lYW4ucltub3QuZXh0aW5jdF0sIG5jbGFzcz0yNSwgY29sPSJkb2RnZXJibHVlIiwgbWFpbj0iIiwNCiMgICAgIHhsYWI9IlBvcHVsYXRpb24gZ3Jvd3RoIHJhdGUiLCBheGVzPUZBTFNFKQ0KIyBheGlzKDEpDQojIGF4aXMoMiwgYXQ9YygwLCAyMDAwLCA0MDAwLCA2MDAwLCA4MDAwLCAxMDAwMCksIGxhYmVscz1jKDAsIDIsIDQsIDYsIDgsIDEwKSkNCiMgbXRleHQoIkMiLCBhdD1hJG1pZHNbMV0sIGNleD0xLjUpDQojIHBhcihvcCkNCiMgfn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn4NCg0KIyBodHRwczovL2dpdGh1Yi5jb20vbWlrZW1lcmVkaXRoL0lQTV9jb2RlL2Jsb2IvbWFpbi9JUE1fMDMvSVBNXzAzLjMuNS5SDQoNCg0KYGBgDQoNCg0KDQoNCg0KIyMjIyB0cmVhdG1lbnQgY29tcGFyaXNvbnMgIA0KDQoNCmBgYHtyfQ0KDQojICMgZm9yIGFjdHVhbCB0cmVhdG1lbnQgZmVjdW5kaXR5IHZhbHVlcw0KIyBjb250bTIgPC0gb3V0MSRtZWFuJGxhbWJkYVsxXSAjMi41NzUNCiMgbG93bTIgPC0gb3V0MSRtZWFuJGxhbWJkYVs3XSAjMi4yNjQNCiMgbWVkbTIgPC0gb3V0MSRtZWFuJGxhbWJkYVsxNF0gIzEuNjA1DQojIGhpZ2htMiA8LSBvdXQxJG1lYW4kbGFtYmRhWzIwXSAjMC4zNDMNCiMgYWxwaGEgPC0gb3V0MSRtZWFuJGFscGhhICMwLjk0MjIyMzQNCiMgYmV0YSA8LSBvdXQxJG1lYW4kYmV0YSAjLTEuMDczMjkzDQoNCnByb2JvZmV4dGluY3RkZiA8LSBkYXRhLmZyYW1lKA0KICB0cmVhdG1lbnQ9YyhyZXAoIkNvbnRyb2wiLDEwKSxyZXAoIkxvdyIsMTApLHJlcCgiTWVkaXVtIiwgMTApLCByZXAoIkhpZ2giLDEwKSksDQogIHRpbWU9cmVwKDE6MTAsIDQpLA0KICBwcm9iZXh0aW5jdD1jKDAuMDI0MSwwLjA4OTYsIDAuMTc5NSwgMC4yNjIwLCAwLjM0NDMsIDAuNDEyOCwgMC40NzYyLCAwLjUyNjQsIDAuNTY3NywgMC42MDI3LA0KICAgICAgICAgICAgICAgIDAuMDI1MSwgMC4xMDIyLCAwLjIwMjAsIDAuMjk2NiwgMC4zODA3LCAwLjQ2MDIsIDAuNTIyMiwgMC41NzQ3LCAwLjYxNjksIDAuNjU0NCwNCiAgICAgICAgICAgICAgICAwLjAzMzEsIDAuMTMyMiwgMC4yNTUzLCAwLjM3MjQsIDAuNDY4MiwgMC41NTE2LCAwLjYxOTEsIDAuNjc3MywgMC43MjY4LCAwLjc2NTQsDQogICAgICAgICAgICAgICAgMC4wNTQzLCAwLjIxODgsIDAuNDAzNSwgMC41NjIzLCAwLjY4MjEsIDAuNzcwOCwgMC44MzI0LCAwLjg3NjQsIDAuOTA3OCwgMC45MzA4KSwNCiAgZmVjdW5kaXR5PWMocmVwKDIuNTc1LCAxMCkscmVwKDIuMjY0LDEwKSxyZXAoMS42MDUsMTApLHJlcCgwLjM0MywxMCkpDQopDQoNCmdncGxvdCgpKw0KICBnZW9tX3BvaW50KGRhdGE9cHJvYm9mZXh0aW5jdGRmLCBhZXMoeD10aW1lLCB5PXByb2JleHRpbmN0LCBjb2xvcj1mYWN0b3IodHJlYXRtZW50LCBsZXZlbHM9YygiQ29udHJvbCIsIkxvdyIsIk1lZGl1bSIsIkhpZ2giKSkpKSsNCiAgZ2VvbV9saW5lKGRhdGE9cHJvYm9mZXh0aW5jdGRmLCBhZXMoeD10aW1lLCB5PXByb2JleHRpbmN0LCBjb2xvcj1mYWN0b3IodHJlYXRtZW50LCBsZXZlbHM9YygiQ29udHJvbCIsIkxvdyIsIk1lZGl1bSIsIkhpZ2giKSkpKSsNCiAgbGFicyhjb2xvcj0iIiwgeD0iWWVhciBvZiBzaW11bGF0aW9uIiwgeT0iUHJvcG9ydGlvbiBvZiBzaW11bGF0aW9ucyB3aXRoIE49MCIpKw0KICBzY2FsZV95X2NvbnRpbnVvdXMoYnJlYWtzPWMoMCwgMC4yNSwgMC41LCAwLjc1LCAxLjApLCBsaW1pdHM9YygwLDEpKSsNCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1jKDE6MTApKSsNCiAgdGhlbWVfY2xhc3NpYygpDQoNCnBsb3QocHJvYmV4dGluY3R+ZmVjdW5kaXR5LCBkYXRhPXByb2JvZmV4dGluY3RkZikNCmFibGluZShsbShwcm9iZXh0aW5jdH5mZWN1bmRpdHksIGRhdGE9cHJvYm9mZXh0aW5jdGRmKSkNCmFibGluZShsbShwcm9iZXh0aW5jdH5mZWN1bmRpdHksIGRhdGE9cHJvYm9mZXh0aW5jdGRmfD5maWx0ZXIodGltZT09MTApKSwgY29sPSJyZWQiKQ0KDQpzdW1tYXJ5KGxtKHByb2JleHRpbmN0fmZlY3VuZGl0eSt0aW1lLCBkYXRhPXByb2JvZmV4dGluY3RkZikpDQoNCnN1bW1hcnkobG0ocHJvYmV4dGluY3R+ZmVjdW5kaXR5LCBkYXRhPXByb2JvZmV4dGluY3RkZnw+ZmlsdGVyKHRpbWU9PTEwKSkpDQpzdW1tYXJ5KGxtKHByb2JleHRpbmN0fmZlY3VuZGl0eSwgZGF0YT1wcm9ib2ZleHRpbmN0ZGZ8PmZpbHRlcih0aW1lPT01KSkpDQoNCiMgLTAuMjAqKDEvLTAuMTUyNikNCiMgPSAxLjMxMDYxNg0KIyBBIHJlZHVjdGlvbiBpbiBmZWN1bmRpdHkgb2YgMS4zMSBpcyBleHBlY3RlZCB0byBsZWFkIHRvIGEgMC4yIGluY3JlYXNlIGluIHJpc2sgb2YgTj0wIGluIHRoZSA1dGggb2YgMTAgeWVhcnMNCg0KIyAyLjU3NTA3MjMtMS4zMTA2MTY9MS4yNjQ0NTYNCg0KIyBhbHBoYSA9IDAuOTQyMjIzNA0KIyBiZXRhID0gLTEuMDczMjkzDQoNCiMgKGxvZygxLjI2NDQ1NiktMC45NDIyMjM0KS8tMS4wNzMyOTMgPQ0KIyAwLjY1OTI2MjENCg0KDQoNCmBgYA0KDQoNCg0KDQoNCg0KDQoNCg0K